Merge branch 'edp-punching-feature' into development

This commit is contained in:
2026-08-02 22:39:12 +05:30
130 changed files with 6113 additions and 5152 deletions

9
.gitignore vendored
View File

@@ -28,5 +28,10 @@
/dist/
/nbdist/
/.nb-gradle/
/cygnus-installer/src/test
/cygnus-installer/src/target/
/cygnus-onprem-app/target
/cygnus-cloud-client/target
/cygnus-cloud-service/target
/cygnus-installer/src/target
/cygnus-installer/target
/cygnus-onprem-db/target
/cygnus-lib/target

3
.vscode/launch.json vendored
View File

@@ -61,6 +61,7 @@
"REDIS_PASSWORD": "M@triXR3d1s@6202",
"REDIS_DATABASE": "1",
"REDIS_SSL": "false",
"CYGNUS_QUERY_CACHE_ENABLED": "false",
"CYGNUS_CLOUD_BASE_URL": "http://localhost:8090",
"CYGNUS_TOKEN_URL": "http://localhost:8090/oauth2/token",
"CYGNUS_CLIENT_ID": "matrix",
@@ -68,6 +69,8 @@
"CYGNUS_CLIENT_ASSERTION": "file:${workspaceFolder}/config/clients/matrix/matrix-matrix-delhi-cygnus-01-assertion.jwt",
"CYGNUS_LOGIN_KEY_ID": "cygnus-login-2026-01",
"CYGNUS_LOGIN_PUBLIC_KEY": "file:${workspaceFolder}/config/keys/login-public.pem",
"CYGNUS_PAYLOAD_PRIVATE_KEY": "file:${workspaceFolder}/config/keys/case-save-private.pem",
"CYGNUS_PAYLOAD_PUBLIC_KEY": "file:${workspaceFolder}/config/keys/case-save-public.pem",
"CYGNUS_CLOUD_REQUEST_TIMEOUT": "PT10S",
"CYGNUS_TOKEN_REFRESH_SKEW": "PT30S"
},

View File

@@ -62,4 +62,15 @@ public class CloudIdentityClient {
.bodyToMono(CloudQueryResponse.class))
.timeout(properties.requestTimeout());
}
public Mono<CloudQueryResponse> fetchQuery(String queryKey) {
return tokenProvider.accessToken()
.flatMap(token -> webClient.get()
.uri(properties.baseUri().resolve("/api/v1/queries/key/" + queryKey))
.header(HttpHeaders.AUTHORIZATION, "Bearer " + token)
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(CloudQueryResponse.class))
.timeout(properties.requestTimeout());
}
}

View File

@@ -25,4 +25,10 @@ public class CloudQueryController {
return repository.findEnabled(queryId)
.switchIfEmpty(Mono.error(new QueryNotFoundException(queryId)));
}
@GetMapping("/key/{queryKey}")
public Mono<CloudQuery> queryByKey(@PathVariable String queryKey) {
return repository.findEnabled(queryKey)
.switchIfEmpty(Mono.error(new QueryNotFoundException(queryKey)));
}
}

View File

@@ -10,8 +10,10 @@ public class QueryCatalogRepository {
private static final String INITIALIZE = """
CREATE SCHEMA IF NOT EXISTS platform;
CREATE SEQUENCE IF NOT EXISTS platform.application_query_id_seq;
CREATE TABLE IF NOT EXISTS platform.application_query (
query_id integer PRIMARY KEY,
query_id integer PRIMARY KEY DEFAULT nextval('platform.application_query_id_seq'),
query_key varchar(100),
query_text text NOT NULL,
enabled boolean NOT NULL DEFAULT true,
created_at timestamptz NOT NULL DEFAULT current_timestamp,
@@ -20,7 +22,15 @@ public class QueryCatalogRepository {
CHECK (query_id > 0),
CONSTRAINT ck_platform_application_query_text
CHECK (length(btrim(query_text)) > 0)
)
);
ALTER TABLE platform.application_query
ADD COLUMN IF NOT EXISTS query_key varchar(100);
ALTER TABLE platform.application_query ALTER COLUMN query_id
SET DEFAULT nextval('platform.application_query_id_seq');
CREATE UNIQUE INDEX IF NOT EXISTS ux_platform_application_query_key
ON platform.application_query (query_key) WHERE query_key IS NOT NULL;
SELECT setval('platform.application_query_id_seq',
greatest(coalesce((SELECT max(query_id) FROM platform.application_query), 0) + 1, 1), false)
""";
private static final String FIND = """
SELECT query_id, query_text
@@ -28,6 +38,12 @@ public class QueryCatalogRepository {
WHERE query_id = $1
AND enabled = true
""";
private static final String FIND_BY_KEY = """
SELECT query_id, query_text
FROM platform.application_query
WHERE query_key = $1
AND enabled = true
""";
private final ReactiveDatabaseClient database;
public QueryCatalogRepository(ReactiveDatabaseClient database) {
@@ -45,4 +61,11 @@ public class QueryCatalogRepository {
.map(row -> new CloudQuery(
row.getInteger("query_id"), row.getString("query_text")));
}
public Mono<CloudQuery> findEnabled(String queryKey) {
return database.preparedQuery(FIND_BY_KEY, Tuple.of(queryKey))
.flatMapMany(rows -> reactor.core.publisher.Flux.fromIterable(rows))
.next()
.map(row -> new CloudQuery(row.getInteger("query_id"), row.getString("query_text")));
}
}

View File

@@ -9,4 +9,8 @@ public class QueryNotFoundException extends RuntimeException {
public QueryNotFoundException(int queryId) {
super("Query was not found: " + queryId);
}
public QueryNotFoundException(String queryKey) {
super("Query was not found: " + queryKey);
}
}

View File

@@ -1,7 +1,9 @@
CREATE SCHEMA IF NOT EXISTS platform;
CREATE SEQUENCE IF NOT EXISTS platform.application_query_id_seq;
CREATE TABLE IF NOT EXISTS platform.application_query (
query_id integer PRIMARY KEY,
query_id integer PRIMARY KEY DEFAULT nextval('platform.application_query_id_seq'),
query_key varchar(100),
query_text text NOT NULL,
enabled boolean NOT NULL DEFAULT true,
created_at timestamptz NOT NULL DEFAULT current_timestamp,
@@ -11,3 +13,11 @@ CREATE TABLE IF NOT EXISTS platform.application_query (
CONSTRAINT ck_platform_application_query_text
CHECK (length(btrim(query_text)) > 0)
);
ALTER TABLE platform.application_query
ADD COLUMN IF NOT EXISTS query_key varchar(100);
CREATE UNIQUE INDEX IF NOT EXISTS ux_platform_application_query_key
ON platform.application_query (query_key) WHERE query_key IS NOT NULL;
ALTER TABLE platform.application_query ALTER COLUMN query_id
SET DEFAULT nextval('platform.application_query_id_seq');
SELECT setval('platform.application_query_id_seq',
greatest(coalesce((SELECT max(query_id) FROM platform.application_query), 0) + 1, 1), false);

View File

@@ -0,0 +1,11 @@
-- Stable query key; query_id is generated by PostgreSQL.
BEGIN;
INSERT INTO platform.application_query(query_key, query_text, enabled, created_at, updated_at, ismigrated)
VALUES ('APPLICATION_SAVE',
'procedure!C0L!select * from public.save_application_details(?::jsonb,?::smallint,?::smallint,?::smallint)',
true, clock_timestamp(), clock_timestamp(), true)
ON CONFLICT (query_key) WHERE query_key IS NOT NULL DO UPDATE SET
query_text=excluded.query_text, enabled=true, updated_at=clock_timestamp(), ismigrated=true;
COMMIT;

47
cygnus-lib/pom.xml Normal file
View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.cygnus</groupId>
<artifactId>cygnus-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>cygnus-lib</artifactId>
<packaging>jar</packaging>
<name>Cygnus Shared Library</name>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,101 @@
package lib.constants;
/** Canonical user-facing messages shared by Cygnus applications. */
public enum ApplicationMessage {
BAD_REQUEST(400, "HTTP-400", "Invalid request",
"Cygnus could not process the submitted request.",
"Review the supplied information and try again."),
SESSION_REQUIRED(401, "AUTH-401", "Sign in required",
"Your session is missing or has expired.",
"Sign in again to continue securely."),
ACCESS_DENIED(403, "AUTH-403", "Access denied",
"You do not have permission to open this page.",
"Contact your administrator if this feature should be available to you."),
PAGE_NOT_FOUND(404, "HTTP-404", "Page not found",
"The requested page could not be found.",
"Check the address or return to the application dashboard."),
METHOD_NOT_ALLOWED(405, "HTTP-405", "Action not allowed",
"This page does not support the requested action.",
"Return to the previous page and try an available action."),
CONFLICT(409, "HTTP-409", "Request conflict",
"The request conflicts with the current state of the data.",
"Refresh the page and try again."),
PAYLOAD_TOO_LARGE(413, "HTTP-413", "File is too large",
"The submitted content exceeds the permitted size.",
"Reduce the file size and try again."),
TOO_MANY_REQUESTS(429, "HTTP-429", "Too many requests",
"Cygnus has received too many requests in a short period.",
"Wait briefly before trying again."),
PAYLOAD_INVALID(400, "REQ-4001", "Invalid request details",
"The encrypted request could not be verified.",
"Refresh the page and submit the form again."),
APPLICATION_VALIDATION_FAILED(422, "APP-4221", "Application validation failed",
"One or more application fields contain invalid information.",
"Correct the highlighted fields and submit the application again."),
APPLICATION_ACCESS_DENIED(403, "APP-4031", "Application access denied",
"The selected portfolio or application is not available to your account.",
"Select an authorized portfolio or contact your administrator."),
APPLICATION_SAVE_CONFLICT(409, "APP-4091", "Application save conflict",
"This request was already processed or the application changed.",
"Refresh the application before submitting it again."),
APPLICATION_SAVED(200, "APP-2001", "Application saved",
"The application details were saved successfully.", ""),
APPLICATIONS_LOADED(200, "APP-2002", "Applications loaded",
"The application records were loaded successfully.", ""),
APPLICATION_LOAD_FAILED(500, "APP-5002", "Applications could not be loaded",
"Cygnus could not load the application details.",
"Try again. If the issue continues, share the reference ID with support."),
APPLICATION_SAVE_FAILED(500, "APP-5001", "Application could not be saved",
"Cygnus could not save the application details.",
"Try again. If the issue continues, share the reference ID with support."),
INTERNAL_SERVER_ERROR(500, "HTTP-500", "Something went wrong",
"Cygnus could not complete your request.",
"Try again. If the issue continues, share the reference ID with support."),
BAD_GATEWAY(502, "HTTP-502", "Service response unavailable",
"A required service returned an invalid response.",
"Try again shortly. If the issue continues, contact support."),
SERVICE_UNAVAILABLE(503, "HTTP-503", "Service temporarily unavailable",
"A required Cygnus service is currently unavailable.",
"Wait briefly and try again."),
GATEWAY_TIMEOUT(504, "HTTP-504", "Service response timed out",
"A required service took too long to respond.",
"Try the request again shortly.");
private final int httpStatus;
private final String code;
private final String title;
private final String message;
private final String description;
ApplicationMessage(
int httpStatus, String code, String title, String message, String description) {
this.httpStatus = httpStatus;
this.code = code;
this.title = title;
this.message = message;
this.description = description;
}
public static ApplicationMessage fromHttpStatus(int status) {
return switch (status) {
case 400 -> BAD_REQUEST;
case 401 -> SESSION_REQUIRED;
case 403 -> ACCESS_DENIED;
case 404 -> PAGE_NOT_FOUND;
case 405 -> METHOD_NOT_ALLOWED;
case 409 -> CONFLICT;
case 413 -> PAYLOAD_TOO_LARGE;
case 429 -> TOO_MANY_REQUESTS;
case 502 -> BAD_GATEWAY;
case 503 -> SERVICE_UNAVAILABLE;
case 504 -> GATEWAY_TIMEOUT;
default -> INTERNAL_SERVER_ERROR;
};
}
public int getHttpStatus() { return httpStatus; }
public String getCode() { return code; }
public String getTitle() { return title; }
public String getMessage() { return message; }
public String getDescription() { return description; }
}

View File

@@ -0,0 +1,20 @@
package lib.exceptions;
import lib.constants.ApplicationMessage;
/** Single typed application exception carrying a safe user-facing message. */
public class ApplicationException extends RuntimeException {
private final ApplicationMessage applicationMessage;
public ApplicationException(ApplicationMessage message, String technicalMessage) {
super(technicalMessage);
this.applicationMessage = message;
}
public ApplicationException(ApplicationMessage message, String technicalMessage, Throwable cause) {
super(technicalMessage, cause);
this.applicationMessage = message;
}
public ApplicationMessage getApplicationMessage() { return applicationMessage; }
}

View File

@@ -0,0 +1,12 @@
package lib.models;
/** Consistent API response contract for every migrated workflow. */
public record ApiResponse<T>(boolean success, T data, MessageDetails message) {
public static <T> ApiResponse<T> success(T data, MessageDetails message) {
return new ApiResponse<>(true, data, message);
}
public static <T> ApiResponse<T> failure(MessageDetails message) {
return new ApiResponse<>(false, null, message);
}
}

View File

@@ -0,0 +1,87 @@
package lib.models;
import java.io.Serial;
import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.Map;
import lombok.Getter;
import lombok.Setter;
/** User-editable case initiation data. Identity and audit fields come from UserSession. */
@Getter
@Setter
public class ApplicationDetails implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private Integer applicationId;
private Short portfolioId;
private Short bankBranchId;
private String applicationNumber;
private String bankCode;
private String product;
private String loanAmount;
private String customerName;
private String fatherName;
private String applicationType;
private String category;
private String dateOfBirth;
private String contactPerson;
private String mobileNumber;
private String specialInstruction;
private Boolean residenceVerification;
private Boolean residenceTelephoneVerification;
private Boolean officeVerification;
private Boolean officeTelephoneVerification;
private Boolean propertyVerification;
private Boolean referenceVerification;
private Boolean documentVerification;
private Boolean residenceCoApplicant;
private Boolean residenceCoProprietor;
private Boolean officeCoProprietor;
private Boolean sameResidenceAddress;
private Boolean sameOfficeAddress;
private Boolean samePropertyAddress;
private String residenceAddress1;
private String residenceAddress2;
private String residenceAddress3;
private String residenceLandmark;
private Integer residenceColonyId;
private String residenceCity;
private String residencePincode;
private String residencePhone;
private String companyName;
private String officeAddress1;
private String officeAddress2;
private String officeAddress3;
private String officeLandmark;
private Integer officeColonyId;
private String officeCity;
private String officePincode;
private String department;
private String designation;
private String officePhone;
private String extension;
private String propertyAddress1;
private String propertyAddress2;
private String propertyAddress3;
private String propertyLandmark;
private Integer propertyColonyId;
private String propertyCity;
private String propertyPincode;
private String referenceName1;
private String referenceAddress1;
private String referenceContactNumber1;
private String referenceName2;
private String referenceAddress2;
private String referenceContactNumber2;
private Map<String, String> dynamicFields = new LinkedHashMap<>();
private Boolean autoCutOff;
private Integer formMode;
}

View File

@@ -0,0 +1,4 @@
package lib.models;
/** Data returned after saving a loan-verification application. */
public record ApplicationSaveData(String operation, Integer applicationId, String mvCode) {}

View File

@@ -0,0 +1,16 @@
package lib.models;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/** Result row returned by the application-save database operation. */
@Getter
@Setter
@NoArgsConstructor
public class ApplicationSaveResult {
private String operation;
private Integer applicationId;
private String mvCode;
private String internalUuid;
}

View File

@@ -0,0 +1,23 @@
package lib.models;
import java.util.List;
import java.util.Map;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class CasePunching {
private MessageDetails messageDetails;
private Map<String, String> optionsl;
private Map<String, List<Option>> options;
private List<String> visibleSections;
private Short portfolioId;
private Integer formMode;
private String userId;
private String dynamicFields;
private String dynamicHtml;
private String verificationCaseId;
private String documentCaseId;
}

View File

@@ -0,0 +1,11 @@
package lib.models;
/** Hybrid RSA-OAEP/AES-GCM envelope submitted by the initiation page. */
public record CaseSaveRequest(
String keyId,
String encryptedKey,
String initializationVector,
String encryptedPayload,
String requestId,
String timestamp) {
}

View File

@@ -0,0 +1,15 @@
package lib.models;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/** Existing application details used by the case-initiation duplicate checks. */
public record DuplicateDetailsData(List<Map<String, Object>> records) {
public DuplicateDetailsData {
records = records == null ? List.of() : records.stream()
.map(record -> Collections.unmodifiableMap(new LinkedHashMap<>(record)))
.toList();
}
}

View File

@@ -0,0 +1,19 @@
package lib.models;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@NoArgsConstructor
public class EditCaseSummary {
private String documentCaseId;
private String mvCode;
private String fileNumber;
private String customerName;
private String applicationType;
private String product;
private String receivedOn;
private String punchedBy;
private String branchCode;
private Short portfolioId;
}

View File

@@ -0,0 +1,10 @@
package lib.models;
import java.util.List;
/** Localities returned to the case-initiation autocomplete. */
public record LocalityData(List<LocalityOption> localities) {
public LocalityData {
localities = localities == null ? List.of() : List.copyOf(localities);
}
}

View File

@@ -0,0 +1,4 @@
package lib.models;
/** One company-authorized locality autocomplete result. */
public record LocalityOption(Integer id, String location, String pincode, String city) {}

View File

@@ -0,0 +1,58 @@
package lib.models;
import lib.constants.ApplicationMessage;
import java.io.Serial;
import java.io.Serializable;
import java.time.Instant;
import java.util.Objects;
import java.util.UUID;
import lombok.Getter;
/** Dependency-free error information shared across Cygnus modules. */
@Getter
public final class MessageDetails implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private final int httpStatus;
private final String code;
private final String title;
private final String message;
private final String description;
private final String referenceId;
private final Instant timestamp;
public MessageDetails(ApplicationMessage message) {
this(message.getHttpStatus(), message.getCode(), message.getTitle(),
message.getMessage(), message.getDescription(),
UUID.randomUUID().toString(), Instant.now());
}
private MessageDetails(
int httpStatus,
String code,
String title,
String message,
String description,
String referenceId,
Instant timestamp) {
if (httpStatus < 100 || httpStatus > 599) {
throw new IllegalArgumentException("HTTP status must be between 100 and 599");
}
this.httpStatus = httpStatus;
this.code = required(code, "code");
this.title = required(title, "title");
this.message = required(message, "message");
this.description = description == null ? "" : description.trim();
this.referenceId = required(referenceId, "referenceId");
this.timestamp = Objects.requireNonNull(timestamp, "timestamp");
}
private static String required(String value, String name) {
if (value == null || value.isBlank()) {
throw new IllegalArgumentException(name + " is required");
}
return value.trim();
}
}

View File

@@ -0,0 +1,13 @@
package lib.models;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class Option {
private Object value;
private String label;
private String description;
private String group;
}

View File

@@ -0,0 +1,15 @@
package lib.models;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Collections;
/** Form-shaped punched applications returned to the case-initiation workspace. */
public record PunchedRecordsData(List<Map<String, Object>> records) {
public PunchedRecordsData {
records = records == null ? List.of() : records.stream()
.map(record -> Collections.unmodifiableMap(new LinkedHashMap<>(record)))
.toList();
}
}

View File

@@ -0,0 +1,29 @@
package lib.models;
import java.io.Serial;
import java.io.Serializable;
import lombok.Builder;
import lombok.Value;
/** Immutable, type-safe representation of an authenticated Cygnus user. */
@Value
@Builder
public class UserSession implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
Short companyId;
String companyName;
String companyCode;
Short branchId;
String branchName;
String branchCode;
String branchLocation;
Short userId;
String username;
String userDisplayName;
Short userGroupId;
String userGroupName;
String loginTime;
String menuHtml;
}

View File

@@ -0,0 +1,22 @@
package lib.models;
import lib.constants.ApplicationMessage;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
class MessageDetailsTest {
@Test
void createsAReusableErrorContract() {
MessageDetails details = new MessageDetails(ApplicationMessage.ACCESS_DENIED);
assertEquals(403, details.getHttpStatus());
assertEquals("AUTH-403", details.getCode());
}
@Test
void mapsHttpStatusToCanonicalError() {
assertEquals(ApplicationMessage.PAGE_NOT_FOUND, ApplicationMessage.fromHttpStatus(404));
assertEquals(ApplicationMessage.INTERNAL_SERVER_ERROR,
ApplicationMessage.fromHttpStatus(599));
}
}

View File

@@ -10,7 +10,7 @@
<mvc:annotation-driven/>
<!-- Scan for annotation based controllers -->
<context:component-scan base-package="matrix.nimble" />
<context:component-scan base-package="matrix.nimble,matrix.services" />
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/app/" />

View File

@@ -1,686 +0,0 @@
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@page language="java" session="true" %>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Cygnus 1.0 |
<c:if test="${caseDetails.getFormMode() eq 1}">Add Cases</c:if>
<c:if test="${caseDetails.getFormMode() eq 2}">Edit Details</c:if>
</title>
<script language="javascript" src="/matrix/js/lib/constants.js" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/jquery1.7.2.js" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/ui/uifuncs.js" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/lib/jsfuncs.js" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/ui/msgdialog.js" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/ui/select.js" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/appjs/punching.js" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/validator.js?ver=2" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/ajax.js" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/ajax-dynamic-list.js" type="text/javascript"></script>
<link href="/matrix/css/button.css" rel="stylesheet" type="text/css" />
<link href="/matrix/css/div.css" rel="stylesheet" type="text/css" />
<link href="/matrix/css/textbox.css" rel="stylesheet" type="text/css" />
<link href="/matrix/css/select.css" rel="stylesheet" type="text/css" />
<link href="/matrix/css/table.css" rel="stylesheet" type="text/css" />
<link href="/matrix/css/autocomplete.css" rel="stylesheet" type="text/css" />
<link href="/matrix/css/bootstrap-5.3.8.min.css" rel="stylesheet" type="text/css" />
<link href="/matrix/css/matrix-v2.css?v=6" rel="stylesheet" type="text/css" />
<link href="/matrix/css/matrix-shell-v2.css?v=7" rel="stylesheet" type="text/css" />
<link href="/matrix/css/tool-workspace-v3.css?v=2" rel="stylesheet" type="text/css" />
<link href="/matrix/css/punch-workspace-v3.css?v=1" rel="stylesheet" type="text/css" />
<link href="/matrix/css/add-cases-v4.css?v=1" rel="stylesheet" type="text/css" />
<script src="/matrix/js/matrix-dialog-child.js" type="text/javascript"></script>
<script src="/matrix/js/bootstrap-5.3.8.bundle.min.js" defer></script>
<script src="/matrix/js/matrix-shell-v2.js" defer></script>
<link href="/matrix/css/matrix-frame-dialog.css?v=6" rel="stylesheet" type="text/css" />
<script src="/matrix/js/matrix-frame-dialog.js?v=2" defer></script>
<script src="/matrix/js/matrix-dialog-child.js" type="text/javascript"></script>
<script src="/matrix/js/matrix-accessibility-v1.js?v=1" defer></script>
<link href="/matrix/css/matrix-theme-v2.css?v=4" rel="stylesheet" type="text/css" />
</head>
<body class="matrix-v2 matrix-shell matrix-tool-workspace matrix-punch-workspace matrix-add-cases">
<div id='PageFrame'>
<c:if test="${caseDetails.getFormMode() eq 1}">
<%@ include file="/WEB-INF/app/fragments/app-shell-header.jspf" %>
<%-- Shared shell owns ${Sessvals.menuHtml}. --%>
</c:if>
<div id="formcontainer" class="matrix-tool-workspace__content">
<form:form method="post" name="caseDetails" id="caseDetails" modelAttribute="caseDetails" >
<!-- Common Details (Section1) Visible for all portfolios-->
<div>
<!-- Title -->
<div class="title">
<img class="matrix-title-icon" src="/matrix/images/commondet.png" align="absmiddle" />
<span class="matrix-title-text" align="absmiddle">Common Details</span>
<c:choose>
<c:when test="${caseDetails.getFormMode() eq 1}">
<div class="divselect" id="divportfolio" style="width:167px;position:absolute;top:3px;right:13px;">
<form:select path="PortfolioId" multiple="false" id="portlist" style="width:185px" onchange="SubmitForm('casedet','_parent','caseDetails')">
<form:option value="-1" label="SELECT PORTFOLIO" selected="true"/>
<c:forEach items="${portlist}" var="port">
<form:option value="${port[0]}" label="${port[1]}" />
</c:forEach>
</form:select>
</div>
</c:when>
<c:otherwise>
<form:hidden path="PortfolioId" id="portlist" />
</c:otherwise>
</c:choose>
</div>
<!-- -->
<!-- Form (Section1) -->
<div id="FormPanel1" class="FormPanel">
<table align="center" class="matrix-form-controls" width="99%">
<tr>
<td>
<div class="widget">
<div class="lblcontainer">
MV Code
</div>
<div class="inputcontainer">
<form:input style="width:65px;text-transform:uppercase" readonly="true" path="MvCode" value="${caseDeails.getMvCode()}" />
</div>
</div>
<div class="widget">
<div class="lblcontainer">
Appl No.
</div>
<div class="inputcontainer">
<form:input maxlength="25" style="width:115px;text-transform:uppercase" id="ApplNo" path="ApplNo" value="${caseDetails.getApplNo()}" onblur="if(validate(this,'t','AlphaNumeric')){FindSameDet(this,'A','CustomerName');}" />
</div>
</div>
<div class="widget">
<div class="lblcontainer">
Bank Code
</div>
<div class="inputcontainer">
<form:input maxlength="25" style="width:70px;text-transform:uppercase" path="BankCode" value="${caseDetails.getBankCode()}" onblur="validate(this,'f','AlphaNumeric');" />
</div>
</div>
<div class="widget">
<div class="lblcontainer">
Branch
</div>
<div class="inputcontainer">
<div class="divselect" id="divbranch" style="width:135px;">
<form:select path="BankBranchId" multiple="false" id="branchlist" style="width:153px" onblur="validate(this,'t','');">
<form:option value="-1" label="SELECT" selected="true"/>
<c:forEach items="${branchlist}" var="brnch">
<form:option value="${brnch[0]}" label="${brnch[1]}" />
</c:forEach>
</form:select>
</div>
</div>
</div>
<div class="widget">
<div class="lblcontainer">
Product
</div>
<div class="inputcontainer">
<div class="divselect" id="divproduct" style="width:132px;">
<form:select path="Product" multiple="false" id="prodlist" style="width:150px" onblur="validate(this,'t','');">
<form:option value="-1" label="SELECT" selected="true"/>
<c:forEach items="${prodlist}" var="prod">
<form:option value="${prod[0]}" label="${prod[1]}" />
</c:forEach>
</form:select>
</div>
</div>
</div>
<div class="widget">
<div class="lblcontainer">
Name
</div>
<div class="inputcontainer">
<form:input maxlength="60" style="width:200px" path="CustomerName" value="${caseDetails.getCustomerName()}" onblur="validate(this,'t','AlphaSpace');" />
</div>
</div>
<div class="widget">
<div class="lblcontainer">
Father Name
</div>
<div class="inputcontainer">
<form:input maxlength="25" style="width:145px" path="FatherName" value="${caseDetails.getFatherName()}" onblur="validate(this,'f','AlphaSpace');" />
</div>
</div>
<div class="widget">
<div class="lblcontainer">
App Type
</div>
<div class="inputcontainer">
<div class="divselect" id="divapptype" style="width:135px;">
<form:select path="CustomerType" multiple="false" id="typelist" style="width:153px" onchange="ToggleChks((this.value.toUpperCase()!='APPLICANT' && this.value.toUpperCase()!='-1'),'chksresi!C0L!chksoff!C0L!chksprop!C0L!','!C0L!')" onblur="validate(this,'t','');">
<form:option value="-1" label="SELECT" selected="true"/>
<c:forEach items="${typelist}" var="type">
<form:option value="${type[0]}" label="${type[1]}" />
</c:forEach>
</form:select>
</div>
</div>
</div>
<div class="widget">
<div class="lblcontainer">
Category
</div>
<div class="inputcontainer">
<div class="divselect" id="divcategory" style="width:115px;">
<form:select path="Category" multiple="false" id="catlist" style="width:133px">
<form:option value="-1" label="SELECT" selected="true"/>
<c:forEach items="${catlist}" var="cat">
<form:option value="${cat[0]}" label="${cat[1]}" />
</c:forEach>
</form:select>
</div>
</div>
</div>
<div class="widget">
<div class="lblcontainer">
DOB
</div>
<div class="inputcontainer">
<form:input maxlength="10" style="width:80px" path="DOB" id="dob" value="${caseDetails.getDOB()}" onkeydown="return addSlashes(this,event)" onblur="validate(this,'f','Date')" />
</div>
</div>
<div class="widget">
<div class="lblcontainer">
Mobile No.
</div>
<div class="inputcontainer">
<form:input maxlength="21" style="width:120px" path="MobileNo" value="${caseDetails.getMobileNo()}" onblur="validate(this,'f','AllowWrong');" />
</div>
</div>
<div class="widget">
<div class="lblcontainer">
Loan Amt
</div>
<div class="inputcontainer">
<form:input maxlength="15" style="width:100px" path="LoanAmount" value="${caseDetails.getLoanAmount()}" onblur="validate(this,'f','LoanAmount');" />
</div>
</div>
<div class="widget">
<div class="lblcontainer">
C Person
</div>
<div class="inputcontainer">
<form:input maxlength="25" style="width:200px" path="ContactPerson" value="${caseDetails.getContactPerson()}" onblur="validate(this,'f','AlphaSpace');" />
</div>
</div>
<div class="widget">
<div class="lblcontainer">
Special Inst.
</div>
<div class="inputcontainer">
<form:input maxlength="50" id="splist" style="width:833px" path="SpecialInst" value="${caseDetails.getSpecialInst()}" onblur="validate(this,'f','SplInstruction')" />
</div>
</div>
</td>
</tr>
</table>
</div>
<!-- -->
</div>
<!-- -->
<!-- Residence Details (Section2) Visible for portfolios in which residence visit/ residence TVR could be initiated-->
<div id="section2">
<!-- Title -->
<div class="title">
<img class="matrix-title-icon" src="/matrix/images/resdet.png" />
<span class="matrix-title-text">Residence Details</span>
<div class="divchk" id="ctrldiv">
<form:checkbox path="Rvr" id="chkresi" onclick="HandleClick(this)" />RVR&nbsp;
<form:checkbox path="SameResi" id="chksresi" onclick="return FindSameDet(this,'R','ResiPhone')" /><span id="chksresi">Same Resi</span>
<form:checkbox path="Rtvr" id="chkteler" onclick="HandleClick(this)" /><span id="chkteler">RTV</span>
</div>
</div>
<!-- -->
<!-- Form (Section2) -->
<div id="FormPanel2" class="FormPanel">
<table align="center" class="matrix-form-controls" style="width:100%">
<tr>
<td>
<div class="widget" style="margin-left:2px">
<div class="lblcontainer" style="padding:1px">
House No.
</div>
<br >
<div class="inputcontainer" style="padding:1px">
<form:input readonly="true" maxlength="20" style="width:70px" path="ResiAdd1" value="${caseDetails.getResiAdd1()}" onblur="validate(this,document.getElementById('chkresi').checked ? 't':'f','SplInstruction')" />
</div>
</div>
<div class="widget" style="margin-left:2px">
<div class="lblcontainer" style="padding:1px">
Sub Locality
</div>
<br >
<div class="inputcontainer" style="padding:1px">
<form:input readonly="true" maxlength="70" style="width:180px" path="ResiAdd2" value="${caseDetails.getResiAdd2()}" onblur="validate(this,'f','SplInstruction')" />
</div>
</div>
<div class="widget" style="margin-left:2px">
<div class="lblcontainer" style="padding:1px">
City
</div>
<br >
<div class="inputcontainer" style="padding:1px">
<div class="divselect" id="divrcity" style="width:110px;">
<form:select path="ResiCity" multiple="false" id="ResiAdd3_citylist" style="width:128px" onblur="validate(this,document.getElementById('chkresi').checked ? 't':'f','')" >
<form:option value="-1" label="Select" selected="true"/>
<form:option value="Unknown" label="Unknown"/>
<c:forEach items="${citylist}" var="city">
<form:option value="${city[0]}" label="${city[1]}" />
</c:forEach>
</form:select>
</div>
</div>
</div>
<div class="widget" style="margin-left:2px">
<div class="lblcontainer" style="padding:1px">
Locality
</div>
<br >
<div class="inputcontainer" style="padding:1px">
<form:input readonly="true" maxlength="50" style="width:180px" path="ResiAdd3" value="${caseDetails.getResiAdd3()}" onkeyup="ajax_showOptions(this,event)" onblur="onLocalityBlur(this,document.getElementById('chkresi').checked ? 't':'f')" />
<form:hidden path="ResiLoc" id="ResiAdd3_hidden" />
</div>
</div>
<div class="widget" style="margin-left:2px">
<div class="lblcontainer" style="padding:1px">
Landmark
</div>
<br >
<div class="inputcontainer" style="padding:1px">
<form:input readonly="true" maxlength="50" style="width:150px" path="ResiLandmark" value="${caseDetails.getResiLandmark()}" onblur="validate(this,'f','SplInstruction')" />
</div>
</div>
<div class="widget" style="margin-left:2px">
<div class="lblcontainer" style="padding:1px">
Pincode
</div>
<br >
<div class="inputcontainer" style="padding:1px">
<form:input readonly="true" maxlength="6" style="width:45px" id="ResiAdd3_Pincode" path="ResiPincode" value="${caseDetails.getResiPincode()}" onblur="validate(this,document.getElementById('chkresi').checked ? 't':'f','Pincode')" />
</div>
</div>
<div class="widget" style="margin-left:2px">
<div class="lblcontainer" style="padding:1px">
Phone No.
</div>
<br >
<div class="inputcontainer" style="padding:1px">
<form:input maxlength="25" style="width:107px" path="ResiPhone" value="${caseDetails.getResiPhone()}" onblur="validate(this,document.getElementById('chkteler').checked ? 't':'f','Phone')" />
</div>
</div>
</td>
</tr>
</table>
</div>
<!-- -->
</div>
<!-- -->
<!-- Office Details (Section3) Visible for portfolios in which office visit/ office TVR could be initiated-->
<div id="section3">
<!-- Title -->
<div class="title">
<img class="matrix-title-icon" src="/matrix/images/optmale.png" />
<span class="matrix-title-text">Office Details</span>
<div class="divchk" id="ctrldiv">
<form:checkbox path="Ovr" id="chkoffice" onclick="HandleClick(this)" />OVR&nbsp;
<form:checkbox path="RCO" id="chkrco" style="display:none" onclick="HandleClick(this)" /><span id="chkrco">RCO</span>&nbsp;
<form:checkbox path="SameOffice" id="chksoff" onclick="return FindSameDet(this,'O','OffPhone')" /><span id="chksoff">Same Office</span>
<form:checkbox path="Otvr" id="chkteleo" onclick="HandleClick(this)" /><span id="chkteleo">OTV</span>
</div>
</div>
<!-- -->
<!-- Form (Section3) -->
<div id="FormPanel3" class="FormPanel">
<table align="center" class="matrix-form-controls">
<tr>
<td>
<div class="widget" style="margin-left:2px">
<div class="lblcontainer" style="padding:1px">
Company
</div>
<br >
<div class="inputcontainer" style="padding:1px">
<form:input maxlength="50" style="width:215px" path="CompanyName" value="${caseDetails.getCompanyName()}" onblur="validate(this,'f','SplInstruction')" />
</div>
</div>
<div class="widget" style="margin-left:2px">
<div class="lblcontainer" style="padding:1px">
Plot No.
</div>
<br >
<div class="inputcontainer" style="padding:1px">
<form:input readonly="true" maxlength="20" style="width:90px" path="OffAdd1" value="${caseDetails.getOffAdd1()}" onblur="validate(this,document.getElementById('chkoffice').checked ? 't':'f','SplInstruction')" />
</div>
</div>
<div class="widget" style="margin-left:2px">
<div class="lblcontainer" style="padding:1px">
Sub Locality
</div>
<br >
<div class="inputcontainer" style="padding:1px">
<form:input readonly="true" maxlength="70" style="width:200px" path="OffAdd2" value="${caseDetails.getOffAdd2()}" onblur="validate(this,'f','SplInstruction')" />
</div>
</div>
<div class="widget" style="margin-left:2px">
<div class="lblcontainer" style="padding:1px">
City
</div>
<br >
<div class="inputcontainer" style="padding:1px">
<div class="divselect" id="divocity" style="width:110px;">
<form:select path="OffCity" multiple="false" id="OffAdd3_citylist" style="width:128px" onblur="validate(this,document.getElementById('chkoffice').checked ? 't':'f','')">
<form:option value="-1" label="Select" selected="true"/>
<form:option value="Unknown" label="Unknown"/>
<c:forEach items="${citylist}" var="city">
<form:option value="${city[0]}" label="${city[1]}" />
</c:forEach>
</form:select>
</div>
</div>
</div>
<div class="widget" style="margin-left:2px">
<div class="lblcontainer" style="padding:1px">
Locality
</div>
<br >
<div class="inputcontainer" style="padding:1px">
<form:input readonly="true" maxlength="50" style="width:200px" path="OffAdd3" value="${caseDetails.getOffAdd3()}" onkeyup="ajax_showOptions(this,event)" onblur="validate(this,document.getElementById('chkoffice').checked ? 't':'f','SplInstruction')" />
<form:hidden path="OffLoc" id="OffAdd3_hidden" />
</div>
</div>
<div class="widget" style="margin-left:2px">
<div class="lblcontainer" style="padding:1px">
Pincode
</div>
<br >
<div class="inputcontainer" style="padding:1px">
<form:input readonly="true" maxlength="6" style="width:45px" id="OffAdd3_Pincode" path="OffPincode" value="${caseDetails.getOffPincode()}" onblur="validate(this,document.getElementById('chkoffice').checked ? 't':'f','Pincode')" />
</div>
</div>
<div class="widget" style="margin-left:2px">
<div class="lblcontainer" style="padding:1px">
Landmark
</div>
<br >
<div class="inputcontainer" style="padding:1px">
<form:input maxlength="50" style="width:215px" path="OffLandmark" value="${caseDetails.getOffLandmark()}" onblur="validate(this,'f','SplInstruction')" />
</div>
</div>
<div class="widget" style="margin-left:2px">
<div class="lblcontainer" style="padding:1px">
Department
</div>
<br >
<div class="inputcontainer" style="padding:1px">
<form:input maxlength="25" style="width:200px" path="Department" value="${caseDetails.getDepartment()}" onblur="validate(this,'f','SplInstruction')" />
</div>
</div>
<div class="widget" style="margin-left:2px">
<div class="lblcontainer" style="padding:1px">
Designation
</div>
<br >
<div class="inputcontainer" style="padding:1px">
<form:input maxlength="25" style="width:210px" path="Designation" value="${caseDetails.getDesignation()}" onblur="validate(this,'f','SplInstruction')" />
</div>
</div>
<div class="widget" style="margin-left:2px">
<div class="lblcontainer" style="padding:1px">
Office Phone-Extn
</div>
<br >
<div class="inputcontainer" style="padding:1px">
<form:input maxlength="25" style="width:150px" path="OffPhone" value="${caseDetails.getOffPhone()}" onblur="validate(this,document.getElementById('chkteleo').checked ? 't':'f','Phone')" />-<form:input type="text" style="width:23px" path="Extension" value="${caseDetails.getExtension()}" onblur="validate(this,'f','Extension')" />
</div>
</div>
</td>
</tr>
</table>
</div>
<!-- -->
</div>
<!-- -->
<!-- Property Details (Section4) Visible for portfolios in which property visit could be initiated-->
<div id="section4">
<!-- Title -->
<div class="title">
<img class="matrix-title-icon" src="/matrix/images/resdet.png" />
<span class="matrix-title-text">Property Details</span>
<div class="divchk" id="ctrldiv">
<form:checkbox path="Pvr" id="chkprop" onclick="HandleClick(this)" />PVR&nbsp;
<form:checkbox path="RCP" id="chkrcp" style="display:none" onclick="HandleClick(this)" /><span id="chkrcp">RCP</span>&nbsp;
<form:checkbox path="OCP" id="chkocp" style="display:none" onclick="HandleClick(this)" /><span id="chkocp">OCP</span>&nbsp;
<form:checkbox path="SameProp" id="chksprop" onclick="return FindSameDet(this,'P','PropAdd3_Pincode')" /><span id="chksprop">Same Property</span>
</div>
</div>
<!-- -->
<!-- Form (Section4) -->
<div id="FormPanel4" class="FormPanel">
<table align="center" class="matrix-form-controls">
<tr>
<td>
<div class="widget" style="margin-left:2px">
<div class="lblcontainer" style="padding:1px">
House / Plot No.
</div>
<br >
<div class="inputcontainer" style="padding:1px">
<form:input readonly="true" maxlength="20" style="width:120px" path="PropAdd1" value="${caseDetails.getPropAdd1()}" onblur="validate(this,document.getElementById('chkprop').checked ? 't':'f','SplInstruction')" />
</div>
</div>
<div class="widget" style="margin-left:2px">
<div class="lblcontainer" style="padding:1px">
Sub Locality
</div>
<br >
<div class="inputcontainer" style="padding:1px">
<form:input readonly="true" maxlength="70" style="width:200px" path="PropAdd2" value="${caseDetails.getPropAdd2()}" onblur="validate(this,'f','SplInstruction')" />
</div>
</div>
<div class="widget" style="margin-left:2px">
<div class="lblcontainer" style="padding:1px">
City
</div>
<br >
<div class="inputcontainer" style="padding:1px">
<div class="divselect" id="divpcity" style="width:110px;">
<form:select path="PropCity" multiple="false" id="PropAdd3_citylist" style="width:128px" onblur="validate(this,document.getElementById('chkprop').checked ? 't':'f','')">
<form:option value="-1" label="Select" selected="true"/>
<form:option value="Unknown" label="Unknown"/>
<c:forEach items="${citylist}" var="city">
<form:option value="${city[0]}" label="${city[1]}" />
</c:forEach>
</form:select>
</div>
</div>
</div>
<div class="widget" style="margin-left:2px">
<div class="lblcontainer" style="padding:1px">
Locality
</div>
<br >
<div class="inputcontainer" style="padding:1px">
<form:input readonly="true" maxlength="50" style="width:200px" path="PropAdd3" value="${caseDetails.getPropAdd3()}" onkeyup="ajax_showOptions(this,event)" onblur="validate(this,document.getElementById('chkprop').checked ? 't':'f','SplInstruction')" />
<form:hidden path="PropLoc" id="PropAdd3_hidden" />
</div>
</div>
<div class="widget" style="margin-left:2px">
<div class="lblcontainer" style="padding:1px">
Landmark
</div>
<br >
<div class="inputcontainer" style="padding:1px">
<form:input readonly="true" maxlength="50" style="width:180px" path="PropLandmark" value="${caseDetails.getPropLandmark()}" onblur="validate(this,'f','SplInstruction')" />
</div>
</div>
<div class="widget" style="margin-left:2px">
<div class="lblcontainer" style="padding:1px">
Pincode
</div>
<br >
<div class="inputcontainer" style="padding:1px">
<form:input readonly="true" maxlength="6" style="width:45px" id="PropAdd3_Pincode" path="PropPincode" value="${caseDetails.getResiPincode()}" onblur="validate(this,document.getElementById('chkprop').checked ? 't':'f','Pincode')" />
</div>
</div>
</td>
</tr>
</table>
</div>
<!-- -->
</div>
<!-- -->
<!-- Reference Details (Section5) Visible for portfolios in which reference calling could be initiated-->
<div id="section5">
<!-- Title -->
<div class="title">
<img class="matrix-title-icon" src="/matrix/images/ref.png" />
<span class="matrix-title-text">Reference Details</span>
<div class="divchk" id="ctrldiv">
<form:checkbox path="Refvr" id="chkref" onclick="setFormValidation(this,'FormPanel5','Ref1Name,Ref1Address,Ref1Contactno','t,f,t','AlphaSpace,SplInstruction,Phone',false)" />Ref Check&nbsp;
</div>
</div>
<!-- -->
<!-- Form (Section5) -->
<div id="FormPanel5" class="FormPanel">
<table align="center" class="matrix-form-controls">
<tr>
<td>&nbsp;</td>
<td>Name</td>
<td>Address</td>
<td>Contact Numbers</td>
</tr>
<tr>
<td>Reference 1&nbsp;</td>
<td><form:input maxlength="30" style="width:200px" path="Ref1Name" value="${caseDetails.getRef1Name()}" onblur="validate(this,document.getElementById('chkref').checked ? 't':'f','AlphaSpace')" /></td>
<td><form:input maxlength="100" style="width:450px" path="Ref1Address" value="${caseDetails.getRef1Address()}" onblur="validate(this,'f','SplInstruction')" /></td>
<td><form:input maxlength="25" style="width:160px" path="Ref1Contactno" value="${caseDetails.getRef1Contactno()}" onblur="validate(this,document.getElementById('chkref').checked ? 't':'f','Phone')" /></td>
</tr>
<tr>
<td>&nbsp;</td>
<td>Name</td>
<td>Address</td>
<td>Contact Numbers</td>
</tr>
<tr>
<td>Reference 2&nbsp;</td>
<td><form:input maxlength="30" style="width:200px" path="Ref2Name" value="${caseDetails.getRef2Name()}" onblur="validate(this,'f','AlphaSpace')" /></td>
<td><form:input maxlength="100" style="width:450px" path="Ref2Address" value="${caseDetails.getRef2Address()}" onblur="validate(this,'f','SplInstruction')" /></td>
<td><form:input maxlength="25" style="width:160px" path="Ref2Contactno" value="${caseDetails.getRef2Contactno()}" onblur="validate(this,'f','Phone')" /></td>
</tr>
</table>
</div>
<!-- -->
</div>
<!-- -->
<!-- Dynamic Form (Section6). All controls under this section will be generated dynamically during runtime-->
<div id="section6">
<!-- Title -->
<div class="title">
<img class="matrix-title-icon" src="/matrix/images/othdet.png" />
<span class="matrix-title-text">Other Details</span>
</div>
<!-- -->
<div id="FormPanel6" class="FormPanel">
${caseDetails.getDynamicPanel()}
</div>
</div>
<!-- -->
<!-- Document Details (Section7) Visible for portfolios in which document verification could be done-->
<div id="section7">
<!-- Title -->
<div class="title">
<img class="matrix-title-icon" src="/matrix/images/documents.png" />
<span class="matrix-title-text">Document Details</span>
<div class="divchk" id="ctrldiv">
<form:checkbox path="Docvr" id="chkdoc" onclick="hideForm(this.id,'FormPanel7')" />Doc VR&nbsp;
</div>
</div>
<!-- -->
<!-- Form (Section7) -->
<div id="FormPanel7" class="FormPanel">
<table align="center" class="matrix-form-controls">
<tr>
<td>Document</td>
<td>Vendor</td>
<td>Service Provider</td>
<td>Name</td>
<td>Unique No.</td>
</tr>
<tr>
<td>
<div class="divselect" id="divdoclist" style="width:90px;">
<select id="doclist" style="width:108px">
<option value="-1" selected="true">
<c:forEach items="${doclist}" var="doc">
<option value="${doc[0]}" >${doc[1]}</option>
</c:forEach>
</select>
</div>
</td>
<td><input type="text" style="width:150px" value="" id="vendor" /></td>
<td><input type="text" style="width:200px" value="" id="serviceprovider" /></td>
<td><input type="text" style="width:200px" value="" id="name" /></td>
<td><input type="text" style="width:180px" value="" id="uniqueno" /></td>
</tr>
</table>
</div>
<!-- -->
</div>
<form:hidden path="DynamicFields" value="${caseDetails.getDynamicFields()}" />
<form:hidden path="VisibleContents" value="${caseDetails.getVisibleContents()}" />
<form:hidden path="FormMode" />
<form:hidden path="UUID" />
<form:hidden path="CaseId" />
<!-- -->
<input type="hidden" id="invalidfields" value="0" />
<c:if test="${caseDetails.getFormMode() eq 2}">
<input type="button" class="button" name="btncancel" style="margin-left:1px;margin-top:5px;float:right" value="Cancel" id="btncancel" accesskey="C" onclick="MatrixDialog.close(0)" />
</c:if>
<input type="button" class="button" name="btnsave" style="margin-top:5px;float:right" value="Save" id="btnsave" accesskey="S" onclick="return ValidateSubmitForm('caseDetails');" />
</form:form>
</div>
</div>
</body>
<!-- Page Load Javascript -->
<script language="javascript" type="text/javascript">
HideSections('rtv');
HideSections('otv');
HideSections('section');
UnhideSections('${visibleContents}','!C0L!');
hideForm('chkresi','FormPanel2');
hideForm('chkoffice','FormPanel3');
hideForm('chkprop','FormPanel4');
hideForm('chkref','FormPanel5');
hideForm('chkdoc','FormPanel7');
ToggleChks((document.getElementById('chkresi').checked && document.getElementById('chkoffice').checked),'chkrco'+ColDelim,ColDelim);
ToggleChks((document.getElementById('chkresi').checked),'chkrcp'+ColDelim,ColDelim);
ToggleChks((document.getElementById('chkoffice').checked),'chkocp'+ColDelim,ColDelim);
ToggleChks((document.getElementById('typelist').value.toUpperCase()!='APPLICANT' && document.getElementById('typelist').value.toUpperCase()!='-1'),'chksresi!C0L!chksoff!C0L!chksprop!C0L!','!C0L!');
document.getElementById('ApplNo').focus();
</script>
<!-- -->
<!-- Process Message -->
<c:if test="${not empty caseDetails.getErrMsg()}">
<script language="javascript" type="text/javascript"> CallMessage('${caseDetails.getErrMsg()}',3000,200,300); </script>
<c:if test="${caseDetails.isProcessFlag()==true and caseDetails.getFormMode()==2}">
<script language="javascript" type="text/javascript">MatrixDialog.close(1);</script>
</c:if>
</c:if>
<!-- -->
</html>

View File

@@ -13,7 +13,7 @@
<script language="javascript" src="/matrix/js/lib/jsfuncs.js" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/ui/msgdialog.js" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/ui/select.js" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/appjs/editcases.js" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/edp/punching/edit-cases.js?ver=1" type="text/javascript"></script>
<link href="/matrix/css/div.css" rel="stylesheet" type="text/css" />
<link href="/matrix/css/select.css" rel="stylesheet" type="text/css" />
@@ -21,11 +21,10 @@
<link href="/matrix/css/bootstrap-5.3.8.min.css" rel="stylesheet" type="text/css" />
<link href="/matrix/css/matrix-v2.css?v=6" rel="stylesheet" type="text/css" />
<link href="/matrix/css/tool-workspace-v3.css?v=2" rel="stylesheet" type="text/css" />
<link href="/matrix/css/edit-cases-v1.css?v=1" rel="stylesheet" type="text/css" />
<title>Cygnus 1.0 | Edit Cases</title>
<script src="/matrix/js/matrix-accessibility-v1.js?v=1" defer></script>
<link href="/matrix/css/matrix-theme-v2.css?v=4" rel="stylesheet" type="text/css" />
<link href="/matrix/css/edit-cases-v1.css?v=8" rel="stylesheet" type="text/css" />
</head>
<body class="matrix-shell matrix-v2 matrix-tool-workspace matrix-edit-cases">
<div id='PageFrame'>
@@ -33,22 +32,22 @@
<%@ include file="/WEB-INF/app/fragments/app-title.jspf" %>
<!-- -->
<div id="formcontainer" class="matrix-tool-workspace__content">
<form:form method="post" name="caseGrid" id="caseGrid" modelAttribute="caseGrid" target="_blank">
<form:form method="post" name="caseGrid" id="caseGrid" modelAttribute="caseGrid" target="_parent">
<!-- Common Details (Section1) Visible for all portfolios-->
<div>
<!-- Title -->
<div class="title">
<img class="matrix-title-icon" src="/matrix/images/commondet.png" align="absmiddle" />
<span class="matrix-title-text" align="absmiddle">List of Cases</span>
<div class="divselect" id="divportfolio" style="width:167px;position:absolute;top:3px;right:30px;">
<form:select path="PortfolioId" multiple="false" id="portlist" style="width:185px" onchange="SubmitForm('caselist','_parent','caseGrid')">
<form:select path="PortfolioId" multiple="false" id="portlist" cssClass="matrix-edit-cases__portfolio-select" onchange="SubmitForm('caselist','_parent','caseGrid')">
<form:option value="-1" label="SELECT PORTFOLIO" selected="true"/>
<c:forEach items="${portlist}" var="port">
<form:option value="${port[0]}" label="${port[1]}" />
<form:option value="${port.value}" label="${port.label}" />
</c:forEach>
</form:select>
</div>
<img class="matrix-title-action" src="/matrix/images/reload.png" title="Refresh Grid" onclick="SubmitForm('caselist','_parent','caseGrid')"/>
<button class="matrix-edit-cases__refresh" type="button" title="Refresh Grid" onclick="SubmitForm('caselist','_parent','caseGrid')">
<img src="/matrix/images/reload.png" alt="" />
</button>
</div>
<!-- -->
<div id="TablePanel" class="tableContainer">
@@ -71,17 +70,17 @@
<c:forEach items="${caseList}" var="casedet" varStatus="status">
<tr id="row${status.count}" tabindex="0" title="Open this case for editing">
<td>
<input type="hidden" name="row${status.count}uuid" id="row${status.count}uuid" value="${casedet[0]}" />
<input type="hidden" name="row${status.count}portid" id="row${status.count}portid" value="${casedet[9]}" />
<input type="hidden" name="row${status.count}uuid" id="row${status.count}uuid" value="${casedet.documentCaseId}" />
<input type="hidden" name="row${status.count}portid" id="row${status.count}portid" value="${casedet.portfolioId}" />
${status.count}</td>
<td>${casedet[1]}</td>
<td>${casedet[2]}</td>
<td>${casedet[3]}</td>
<td>${casedet[4]}</td>
<td>${casedet[5]}</td>
<td>${casedet[6]}</td>
<td>${casedet[7]}</td>
<td>${casedet[8]}</td>
<td>${casedet.mvCode}</td>
<td>${casedet.fileNumber}</td>
<td>${casedet.customerName}</td>
<td>${casedet.applicationType}</td>
<td>${casedet.product}</td>
<td>${casedet.receivedOn}</td>
<td>${casedet.punchedBy}</td>
<td>${casedet.branchCode}</td>
</tr>
</c:forEach>
</tbody>

View File

@@ -3,6 +3,12 @@
<%@page language="java" session="true" %>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<c:set var="pageFormMode" value="${not empty model ? model.formMode : formmode}" />
<c:set var="pagePortfolioId" value="${not empty model ? model.portfolioId : portfolio_id}" />
<c:set var="pageDynamicFields" value="${not empty model ? model.dynamicFields : dynamicfields}" />
<c:set var="pageDocumentCaseId" value="${not empty model ? model.documentCaseId : duuid}" />
<c:set var="pageUserId" value="${not empty model ? model.userId : usid}" />
<!DOCTYPE html>
<html>
<head>
@@ -12,12 +18,16 @@
<script language="javascript" src="/matrix/js/jquery1.7.2.js" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/ui/uifuncs.js" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/lib/jsfuncs.js" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/lib/notifications.js?ver=1" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/lib/payload-crypto.js?ver=1" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/lib/form-validation.js?ver=1" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/ui/msgdialog.js" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/ui/select.js" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/appjs/punching.js?ver=4" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/validator.js" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/ajax.js" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/ajax-dynamic-list.js?ver=1" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/edp/punching/initiation.js?ver=8" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/edp/punching/initiation-validation.js?ver=1" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/edp/punching/application-save.js?ver=2" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/validator.js?ver=2" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/ajax-dynamic-list.js?ver=2" type="text/javascript"></script>
<link href="/matrix/css/button.css" rel="stylesheet" type="text/css" />
<link href="/matrix/css/div.css" rel="stylesheet" type="text/css" />
@@ -26,11 +36,11 @@
<link href="/matrix/css/table.css" rel="stylesheet" type="text/css" />
<link href="/matrix/css/autocomplete.css" rel="stylesheet" type="text/css" />
<link href="/matrix/css/bootstrap-5.3.8.min.css" rel="stylesheet" type="text/css" />
<link href="/matrix/css/matrix-v2.css?v=6" rel="stylesheet" type="text/css" />
<link href="/matrix/css/matrix-v2.css?v=7" rel="stylesheet" type="text/css" />
<link href="/matrix/css/matrix-shell-v2.css?v=7" rel="stylesheet" type="text/css" />
<link href="/matrix/css/tool-workspace-v3.css?v=2" rel="stylesheet" type="text/css" />
<link href="/matrix/css/punch-workspace-v3.css?v=1" rel="stylesheet" type="text/css" />
<link href="/matrix/css/add-cases-v4.css?v=1" rel="stylesheet" type="text/css" />
<link href="/matrix/css/punch-workspace-v3.css?v=2" rel="stylesheet" type="text/css" />
<link href="/matrix/css/add-cases-v4.css?v=6" rel="stylesheet" type="text/css" />
<script src="/matrix/js/bootstrap-5.3.8.bundle.min.js" defer></script>
<script src="/matrix/js/matrix-shell-v2.js" defer></script>
<link href="/matrix/css/matrix-frame-dialog.css?v=6" rel="stylesheet" type="text/css" />
@@ -44,10 +54,10 @@
<!-- Title Bar -->
<%@ include file="/WEB-INF/app/fragments/app-title.jspf" %>
<!-- -->
<c:if test="${formmode!=2}">
<c:if test="${pageFormMode!=2}">
<!-- Dynamic Menu -->
<nav class="matrix-shell__navigation" aria-label="Primary navigation">
<c:out value="${Sessvals.menuHtml}" escapeXml="false" />
<c:out value="${sessionScope.userSession.menuHtml}" escapeXml="false" />
</nav>
<!-- -->
</c:if>
@@ -59,21 +69,33 @@
<div class="title matrix-form-title">
<img class="matrix-title-icon" src="/matrix/images/commondet.png" align="absmiddle" />
<span class="matrix-title-text matrix-form-title__heading">Common Details <span id='recfound'></span></span>
<label class="matrix-form-title__field">Skip To <input type="text" class="textbox" style="width:30px" onkeypress="return NumberOnly(event)" onblur="GotoRecord(this,'recno')"></label>
<label class="matrix-form-title__field">Search By File No <input type="text" class="textbox" style="width:100px" onblur="GotoRecord(this,'query')"></label>
<label class="matrix-form-title__field">Skip To <input type="text" class="textbox" style="width:50px" onkeypress="return NumberOnly(event)" onblur="GotoRecord(this,'recno')"></label>
<label class="matrix-form-title__field">Search By File No <input type="text" class="textbox" style="width:150px" onblur="GotoRecord(this,'query')"></label>
<!-- Checkbox for AUTO CUT diabled for now -->
<label class="matrix-form-title__check"><input type="checkbox" name="autocut" checked id="autocut" /> Auto Cut-Off</label>
<c:if test="${formmode==2}">
<input type="hidden" id="portfolio_id" name="portfolio_id" value="-1" />
<c:if test="${pageFormMode==2}">
<input type="hidden" id="portfolio_id" name="portfolioId" value="${pagePortfolioId}" />
<button type="button" class="matrix-edit-back" onclick="history.back()" title="Back to case list">
<span aria-hidden="true">&#8592;</span> Back
</button>
</c:if>
<c:if test="${formmode!=2}">
<div class="divselect matrix-form-title__end" id="divportfolio" style="width:217px;">
<select id="portfolio_id" name="portfolio_id" style="width:235px" onchange="SubmitForm('caseadd','_parent','casedetails')">
<c:if test="${pageFormMode!=2}">
<div class="divselect matrix-form-title__end" id="divportfolio" style="width:297px;">
<select id="portfolio_id" name="portfolioId" style="width:315px" onchange="SubmitForm('caseadd','_parent','casedetails')">
<option value="-1" selected >SELECT PORTFOLIO</option>
<c:forEach items="${portlist}" var="port">
<option value="${port[0]}">${port[1]}</option>
<c:choose>
<c:when test="${not empty model}">
<c:forEach items="${model.options['portfolio.']}" var="port">
<option value="${port.value}"><c:out value="${port.label}" /></option>
</c:forEach>
</c:when>
<c:otherwise>
<c:forEach items="${portlist}" var="port">
<option value="${port[0]}"><c:out value="${port[1]}" /></option>
</c:forEach>
</c:otherwise>
</c:choose>
</select>
</div>
</c:if>
@@ -97,7 +119,7 @@
Appl No.
</div>
<div class="inputcontainer">
<input type="text" id="applno" name="applno" maxlength="25" style="width:115px;text-transform:uppercase" value="" onblur="if(validate(this,'t','AlphaNumeric')){FindSameDet(this,'A','customername');}" />
<input type="text" id="applno" name="applno" maxlength="25" style="width:115px;text-transform:uppercase" value="" onblur="if(CygnusInitiationValidation.validateField(this)){FindSameDet(this,'A','customername');}" />
</div>
</div>
<div class="widget">
@@ -105,7 +127,7 @@
Bank Code
</div>
<div class="inputcontainer">
<input type="text" maxlength="25" id="bankcode" name="bankcode" style="width:70px;text-transform:uppercase" value="" onblur="validate(this,'f','AlphaNumeric');" />
<input type="text" maxlength="25" id="bankcode" name="bankcode" style="width:70px;text-transform:uppercase" value="" onblur="CygnusInitiationValidation.validateField(this);" />
</div>
</div>
<div class="widget">
@@ -114,11 +136,16 @@
</div>
<div class="inputcontainer">
<div class="divselect" id="divbranch" style="width:135px;">
<select id="bank_branch_id" name="bank_branch_id" style="width:153px" onblur="validate(this,'t','');">
<select id="bank_branch_id" name="bank_branch_id" style="width:153px" onblur="CygnusInitiationValidation.validateField(this);">
<option value="-1" selected >SELECT</option>
<c:forEach items="${branchlist}" var="brnch">
<option value="${brnch[0]}">${brnch[1]}</option>
<c:choose>
<c:when test="${not empty model}">
<c:forEach items="${model.options['branch.']}" var="option">
<option value="${option.value}"><c:out value="${option.label}" /></option>
</c:forEach>
</c:when>
<c:otherwise><c:forEach items="${branchlist}" var="brnch"><option value="${brnch[0]}"><c:out value="${brnch[1]}" /></option></c:forEach></c:otherwise>
</c:choose>
</select>
</div>
</div>
@@ -129,11 +156,12 @@
</div>
<div class="inputcontainer">
<div class="divselect" id="divproduct" style="width:132px;">
<select id="product" name="product" style="width:150px" onblur="validate(this,'t','');">
<select id="product" name="product" style="width:150px" onblur="CygnusInitiationValidation.validateField(this);">
<option value="-1" selected >SELECT</option>
<c:forEach items="${prodlist}" var="prod">
<option value="${prod[0]}">${prod[1]}</option>
</c:forEach>
<c:choose>
<c:when test="${not empty model}"><c:forEach items="${model.options['product.']}" var="option"><option value="${option.value}"><c:out value="${option.label}" /></option></c:forEach></c:when>
<c:otherwise><c:forEach items="${prodlist}" var="prod"><option value="${prod[0]}"><c:out value="${prod[1]}" /></option></c:forEach></c:otherwise>
</c:choose>
</select>
</div>
</div>
@@ -143,7 +171,7 @@
Name
</div>
<div class="inputcontainer">
<input type="text" id="customername" name="customername" maxlength="100" style="width:200px" value="" onblur="validate(this,'t','AlphaSpace');" />
<input type="text" id="customername" name="customername" maxlength="100" style="width:200px" value="" onblur="CygnusInitiationValidation.validateField(this);" />
</div>
</div>
<div class="widget">
@@ -160,11 +188,12 @@
</div>
<div class="inputcontainer">
<div class="divselect" id="divapptype" style="width:135px;">
<select id="apptype" name="apptype" style="width:153px" onchange="ToggleChks((this.value.toUpperCase()!='APPLICANT' && this.value.toUpperCase()!='-1'),'sradd!C0L!soadd!C0L!spadd!C0L!','!C0L!')" onblur="validate(this,'t','');">
<select id="apptype" name="apptype" style="width:153px" onchange="ToggleChks((this.value.toUpperCase()!='APPLICANT' && this.value.toUpperCase()!='-1'),['sradd','soadd','spadd'])" onblur="CygnusInitiationValidation.validateField(this);">
<option value="-1" selected>SELECT</option>
<c:forEach items="${typelist}" var="type">
<option value="${type[0]}">${type[1]}</option>
</c:forEach>
<c:choose>
<c:when test="${not empty model}"><c:forEach items="${model.options['applicationType.']}" var="option"><option value="${option.value}"><c:out value="${option.label}" /></option></c:forEach></c:when>
<c:otherwise><c:forEach items="${typelist}" var="type"><option value="${type[0]}"><c:out value="${type[1]}" /></option></c:forEach></c:otherwise>
</c:choose>
</select>
</div>
</div>
@@ -177,9 +206,10 @@
<div class="divselect" id="divcategory" style="width:115px;">
<select id="category" name="category" style="width:133px">
<option value="-1" selected>SELECT</option>
<c:forEach items="${catlist}" var="cat">
<option value="${cat[0]}">${cat[1]}</option>
</c:forEach>
<c:choose>
<c:when test="${not empty model}"><c:forEach items="${model.options['category.']}" var="option"><option value="${option.value}"><c:out value="${option.label}" /></option></c:forEach></c:when>
<c:otherwise><c:forEach items="${catlist}" var="cat"><option value="${cat[0]}"><c:out value="${cat[1]}" /></option></c:forEach></c:otherwise>
</c:choose>
</select>
</div>
</div>
@@ -238,10 +268,10 @@
<div class="title">
<img class="matrix-title-icon" src="/matrix/images/resdet.png" />
<span class="matrix-title-text">Residence Details</span>
<div class="divchk" id="ctrldiv">
<div class="divchk ctrldiv">
<input type="checkbox" id="rv" name="rv" onclick="HandleClick(this)" />RVR&nbsp;
<input type="checkbox" id="sradd" name="rv" onclick="return FindSameDet(this,'R','rphone')" /><span id="sradd">Same Resi</span>
<input type="checkbox" id="rtv" name="rv" onclick="HandleClick(this)" /><span id="rtv">RTV</span>
<input type="checkbox" id="sradd" name="sradd" onclick="return FindSameDet(this,'R','rphone')" /><span id="sradd-label">Same Resi</span>
<input type="checkbox" id="rtv" name="rtv" onclick="HandleClick(this)" /><span id="rtv-label">RTV</span>
</div>
</div>
<!-- -->
@@ -287,9 +317,10 @@
<select id="rcity" name="colr_citylist" style="width:128px" onblur="HandleBlur(this)" >
<option value="-1">Select</option>
<option value="Unknown">Unknown</option>
<c:forEach items="${citylist}" var="city">
<option value="${city[0]}">${city[1]}</option>
</c:forEach>
<c:choose>
<c:when test="${not empty model}"><c:forEach items="${model.options['city.']}" var="option"><option value="${option.value}"><c:out value="${option.label}" /></option></c:forEach></c:when>
<c:otherwise><c:forEach items="${citylist}" var="city"><option value="${city[0]}"><c:out value="${city[1]}" /></option></c:forEach></c:otherwise>
</c:choose>
</select>
</div>
</div>
@@ -345,11 +376,11 @@
<div class="title">
<img class="matrix-title-icon" src="/matrix/images/optmale.png" />
<span class="matrix-title-text">Office Details</span>
<div class="divchk" id="ctrldiv">
<div class="divchk ctrldiv">
<input type="checkbox" id="ov" onclick="HandleClick(this)" />OVR&nbsp;
<input type="checkbox" id="rco" style="display:none" onclick="HandleClick(this)" /><span id="rco">RCO</span>&nbsp;
<input type="checkbox" id="soadd" onclick="return FindSameDet(this,'O','ophone')" /><span id="soadd">Same Office</span>
<input type="checkbox" id="otv" onclick="HandleClick(this)" /><span id="otv">OTV</span>
<input type="checkbox" id="rco" style="display:none" onclick="HandleClick(this)" /><span id="rco-label">RCO&nbsp;</span>
<input type="checkbox" id="soadd" onclick="return FindSameDet(this,'O','ophone')" /><span id="soadd-label">Same Office</span>
<input type="checkbox" id="otv" onclick="HandleClick(this)" /><span id="otv-label">OTV</span>
</div>
</div>
<!-- -->
@@ -404,9 +435,10 @@
<select id="ocity" name="colo_citylist" style="width:128px" onblur="HandleBlur(this)" >
<option value="-1">Select</option>
<option value="Unknown">Unknown</option>
<c:forEach items="${citylist}" var="city">
<option value="${city[0]}">${city[1]}</option>
</c:forEach>
<c:choose>
<c:when test="${not empty model}"><c:forEach items="${model.options['city.']}" var="option"><option value="${option.value}"><c:out value="${option.label}" /></option></c:forEach></c:when>
<c:otherwise><c:forEach items="${citylist}" var="city"><option value="${city[0]}"><c:out value="${city[1]}" /></option></c:forEach></c:otherwise>
</c:choose>
</select>
</div>
</div>
@@ -445,7 +477,7 @@
</div>
<br >
<div class="inputcontainer" style="padding:1px">
<input type="text" id="department" name="designation" maxlength="50" style="width:100px" value="" onblur="validate(this,'f','SplInstruction')" />
<input type="text" id="department" name="department" maxlength="50" style="width:100px" value="" onblur="validate(this,'f','SplInstruction')" />
</div>
</div>
<div class="widget" style="margin-left:2px">
@@ -462,8 +494,10 @@
Office Phone-Extn
</div>
<br >
<div class="inputcontainer" style="padding:1px">
<input type="text" id="ophone" name="ophone" maxlength="25" style="width:100px" value="" onblur="validate(this,document.getElementById('otv').checked ? 't':'f','Phone')" />-<input type="text" id="extension" name="extension" style="width:23px" maxlength="10" value="" onblur="validate(this,'f','Extension')" />
<div class="inputcontainer matrix-phone-extension" style="padding:1px">
<input type="text" id="ophone" name="ophone" maxlength="25" value="" onblur="validate(this,document.getElementById('otv').checked ? 't':'f','Phone')" />
<span aria-hidden="true">-</span>
<input type="text" id="extension" name="extension" maxlength="10" value="" aria-label="Office phone extension" onblur="validate(this,'f','Extension')" />
</div>
</div>
</td>
@@ -480,11 +514,11 @@
<div class="title">
<img class="matrix-title-icon" src="/matrix/images/resdet.png" />
<span class="matrix-title-text">Property Details</span>
<div class="divchk" id="ctrldiv">
<div class="divchk ctrldiv">
<input type="checkbox" id="pv" onclick="HandleClick(this)" />PVR&nbsp;
<input type="checkbox" id="rcp" style="display:none" onclick="HandleClick(this)" /><span id="rcp">RCP</span>&nbsp;
<input type="checkbox" id="ocp" style="display:none" onclick="HandleClick(this)" /><span id="ocp">OCP</span>&nbsp;
<input type="checkbox" id="spadd" onclick="return FindSameDet(this,'P','ppincode')" /><span id="spadd">Same Property</span>
<input type="checkbox" id="rcp" style="display:none" onclick="HandleClick(this)" /><span id="rcp-label">RCP&nbsp;</span>
<input type="checkbox" id="ocp" style="display:none" onclick="HandleClick(this)" /><span id="ocp-label">OCP&nbsp;</span>
<input type="checkbox" id="spadd" onclick="return FindSameDet(this,'P','ppincode')" /><span id="spadd-label">Same Property</span>
</div>
</div>
<!-- -->
@@ -499,7 +533,7 @@
</div>
<br >
<div class="inputcontainer" style="padding:1px">
<input type="text" id="paddr1" name="paddr1" readonly="readonly" maxlength="40" style="width:90px" value="" onblur="validate(this,document.getElementById('rv').checked ? 't':'f','SplInstruction')" />
<input type="text" id="paddr1" name="paddr1" readonly="readonly" maxlength="40" style="width:90px" value="" onblur="CygnusInitiationValidation.validateField(this);" />
</div>
</div>
<div class="widget" style="margin-left:2px">
@@ -530,9 +564,10 @@
<select id="pcity" name="colp_citylist" style="width:128px" onblur="HandleBlur(this)" >
<option value="-1">Select</option>
<option value="Unknown">Unknown</option>
<c:forEach items="${citylist}" var="city">
<option value="${city[0]}">${city[1]}</option>
</c:forEach>
<c:choose>
<c:when test="${not empty model}"><c:forEach items="${model.options['city.']}" var="option"><option value="${option.value}"><c:out value="${option.label}" /></option></c:forEach></c:when>
<c:otherwise><c:forEach items="${citylist}" var="city"><option value="${city[0]}"><c:out value="${city[1]}" /></option></c:forEach></c:otherwise>
</c:choose>
</select>
</div>
</div>
@@ -553,7 +588,7 @@
</div>
<br >
<div class="inputcontainer" style="padding:1px">
<input type="text" id="ppincode" name="colp_pincode" readonly="readonly" maxlength="6" style="width:45px" value="" onblur="validate(this,document.getElementById('rv').checked ? 't':'f','Pincode')" />
<input type="text" id="ppincode" name="colp_pincode" readonly="readonly" maxlength="6" style="width:45px" value="" onblur="CygnusInitiationValidation.validateField(this);" />
</div>
</div>
<div class="widget" style="margin-left:2px">
@@ -579,7 +614,7 @@
<div class="title">
<img class="matrix-title-icon" src="/matrix/images/ref.png" />
<span class="matrix-title-text">Reference Details</span>
<div class="divchk" id="ctrldiv">
<div class="divchk ctrldiv">
<input type="checkbox" id="refv" name="refv" onclick="HandleClick(this)" />Ref Check&nbsp;
</div>
</div>
@@ -621,12 +656,15 @@
<div id="section6">
<!-- Title -->
<div class="title">
<img class="matrix-title-icon" src="/matrix/images/othdet.png" />
<img class="matrix-title-icon" src="/matrix/images/edit_form.png" alt="" />
<span class="matrix-title-text">Other Details</span>
</div>
<!-- -->
<div id="FormPanel6" class="FormPanel">
${dynamichtml}
<c:choose>
<c:when test="${not empty model}"><c:out value="${model.dynamicHtml}" escapeXml="false" /></c:when>
<c:otherwise><c:out value="${dynamichtml}" escapeXml="false" /></c:otherwise>
</c:choose>
<br/>
<br/>
<br/>
@@ -641,7 +679,7 @@
<div class="title">
<img class="matrix-title-icon" src="/matrix/images/documents.png" />
<span class="matrix-title-text">Document Details</span>
<div class="divchk" id="ctrldiv">
<div class="divchk ctrldiv">
<input type="checkbox" name="docv" id="docv" />Doc VR&nbsp;
</div>
</div>
@@ -650,42 +688,65 @@
<br />
<br />
<br />
<input type="hidden" id="dynamicfields" name="dynamicfields" value="${dynamicfields}" />
<input type="hidden" id="dynamicfields" name="dynamicfields" value="${pageDynamicFields}" />
<input type="hidden" id="visiblecontents" name="visiblecontents" value="${visiblecontents}" />
<input type="hidden" id="uuid" name="uuid" value="${duuid}" />
<input type="hidden" id="initial-portfolio-id" value="${pagePortfolioId}" />
<c:if test="${not empty model}">
<c:forEach items="${model.visibleSections}" var="section">
<span hidden class="model-visible-section"><c:out value="${section}" /></span>
</c:forEach>
</c:if>
<input type="hidden" id="uuid" name="uuid" value="${pageDocumentCaseId}" />
<input type="hidden" id="case_id" name="case_id" value="" />
<input type="hidden" id="company_id" name="company_id" value="${Sessvals.getCompanyID()}" />
<input type="hidden" id="branch_id" name="branch_id" value="${Sessvals.getBranchID()}" />
<input type="hidden" id="company_id" name="company_id" value="${sessionScope.userSession.companyId}" />
<input type="hidden" id="branch_id" name="branch_id" value="${sessionScope.userSession.branchId}" />
<input type="hidden" id="status" name="status" value="" />
<!-- -->
<input type="hidden" id="invalidfields" value="0" />
<c:if test="${formmode gt 0}">
<c:if test="${pageFormMode gt 0}">
<div style="position:fixed;text-align:right;bottom:0px;width:980px;" class="buttonbar">
<input type="hidden" id="invalidfields" value="0" />
<input type="button" class="button" name="btnfirst" style="margin-left:5px;margin-top:-2px;float:left;width:80px" value="" id="btnfirst" accesskey="F" onclick="findRecord(1)" />
<input type="button" class="button" name="btnprev" style="margin-top:-2px;float:left;width:80px" value="" id="btnprev" accesskey="P" onclick="findRecord(2)" />
<input type="button" class="button" name="btnnext" style="margin-top:-2px;float:left;width:80px" value="" id="btnnext" accesskey="N" onclick="findRecord(3)" />
<input type="button" class="button" name="btnlast" style="margin-top:-2px;float:left;width:80px" value="" id="btnlast" accesskey="L" onclick="findRecord(4)" />
<input type="button" class="button" name="btnsave" style="float:right" value="Save" id="btnsave" accesskey="S" onclick="return ValidateSubmitForm('casedetails');" />
<c:if test="${formmode!=2}">
<input type="button" class="button" name="btnsave" style="float:right" value="Save" id="btnsave" accesskey="S" onclick="return CygnusInitiation.save(event);" />
<c:if test="${pageFormMode!=2}">
<input type="button" class="button" name="btnadd" style="float:right" value="Add" id="btnadd" accesskey="A" onclick="return AddNewRecord();" />
</c:if>
</div>
</c:if>
</form>
<input type="hidden" id="formmode" name="formmode" value="${formmode}" />
<input type="hidden" id="usid" name="usid" value="${usid}" />
<input type="hidden" id="formmode" name="formmode" value="${pageFormMode}" />
<input type="hidden" id="usid" name="usid" value="${pageUserId}" />
<c:if test="${not empty model.messageDetails}">
<span id="page-error-code" hidden><c:out value="${model.messageDetails.code}" /></span>
<span id="page-error-message" hidden><c:out value="${model.messageDetails.message}" /></span>
</c:if>
</div>
</div>
</body>
<!-- Page Load Javascript -->
<script language="javascript" type="text/javascript">
InitPage('${portfolio_id}','${visiblecontents}');
(function () {
CygnusInitiationValidation.bind(document.getElementById("casedetails"));
var sectionFields = document.querySelectorAll(".model-visible-section");
if (sectionFields.length > 0) {
document.getElementById("visiblecontents").value = Array.prototype.map.call(
sectionFields, function (field) { return field.textContent; }
).join(ColDelim);
}
InitPage();
var code = document.getElementById("page-error-code");
var errorMessage = document.getElementById("page-error-message");
if (code && errorMessage) {
CygnusNotifications.show({
type: "danger", code: code.textContent,
message: errorMessage.textContent, duration: 3000
});
}
}());
</script>
<!-- -->
<!-- Process Message -->
<c:if test="${not empty msg}">
<script language="javascript" type="text/javascript"> CallMessage('${msg}',3000,200,300); </script>
</c:if>
<!-- -->
</html>

View File

@@ -1,329 +0,0 @@
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@page language="java" session="true" %>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Cygnus 1.0 | Document Initiation </title>
<script language="javascript" src="/matrix/js/lib/constants.js" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/jquery1.7.2.js" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/ui/uifuncs.js" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/lib/jsfuncs.js" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/ui/msgdialog.js" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/ui/select.js" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/ajax.js" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/ajax-dynamic-list.js" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/appjs/punchingdoc.js" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/validator.js" type="text/javascript"></script>
<link href="/matrix/css/button.css" rel="stylesheet" type="text/css" />
<link href="/matrix/css/div.css" rel="stylesheet" type="text/css" />
<link href="/matrix/css/textbox.css" rel="stylesheet" type="text/css" />
<link href="/matrix/css/select.css" rel="stylesheet" type="text/css" />
<link href="/matrix/css/table.css" rel="stylesheet" type="text/css" />
<link href="/matrix/css/autocomplete.css" rel="stylesheet" type="text/css" />
<link href="/matrix/css/bootstrap-5.3.8.min.css" rel="stylesheet" type="text/css" />
<link href="/matrix/css/matrix-v2.css?v=6" rel="stylesheet" type="text/css" />
<link href="/matrix/css/matrix-shell-v2.css?v=7" rel="stylesheet" type="text/css" />
<link href="/matrix/css/tool-workspace-v3.css?v=2" rel="stylesheet" type="text/css" />
<link href="/matrix/css/punch-workspace-v3.css?v=1" rel="stylesheet" type="text/css" />
<link href="/matrix/css/add-cases-v4.css?v=1" rel="stylesheet" type="text/css" />
<script src="/matrix/js/bootstrap-5.3.8.bundle.min.js" defer></script>
<script src="/matrix/js/matrix-shell-v2.js" defer></script>
<link href="/matrix/css/matrix-frame-dialog.css?v=6" rel="stylesheet" type="text/css" />
<script src="/matrix/js/matrix-frame-dialog.js?v=2" defer></script>
<script src="/matrix/js/matrix-accessibility-v1.js?v=1" defer></script>
<link href="/matrix/css/matrix-theme-v2.css?v=4" rel="stylesheet" type="text/css" />
</head>
<body class="matrix-v2 matrix-shell matrix-tool-workspace matrix-punch-workspace matrix-add-cases">
<div id='PageFrame'>
<%@ include file="/WEB-INF/app/fragments/app-shell-header.jspf" %>
<%-- Shared shell owns ${Sessvals.menuHtml}. --%>
<div id="formcontainer" class="matrix-tool-workspace__content">
<form method="post" name="docdetails" id="docdetails" >
<!-- Common Details (Section1) Visible for all portfolios-->
<div>
<!-- Title -->
<div class="title matrix-form-title">
<img class="matrix-title-icon" src="/matrix/images/commondet.png" align="absmiddle" />
<span class="matrix-title-text matrix-form-title__heading">Common Details <span id='recfound'></span></span>
<label class="matrix-form-title__field">Skip To <input type="text" class="textbox" style="width:30px" onkeypress="return NumberOnly(event)" onblur="GotoRecord(this)"></label>
<label class="matrix-form-title__field">Search by File No <input type="text" class="textbox" style="width:200px" onblur="SearchRecord(this)"></label>
<!-- Checkbox for AUTO CUT diabled for now -->
<!-- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" name="autocut" id="autocut" />&nbsp;Automatic Cut-Off -->
<div class="divselect matrix-form-title__end" id="divportfolio" style="width:167px;">
<select id="portfolio_id" name="portfolio_id" style="width:185px" onchange="SubmitForm('docadd','_parent','docdetails')">
<option value="-1" selected >SELECT PORTFOLIO</option>
<c:forEach items="${portlist}" var="port">
<option value="${port[0]}">${port[1]}</option>
</c:forEach>
</select>
</div>
</div>
<!-- -->
<!-- Form (Section1) -->
<div id="FormPanel1" class="FormPanel">
<table align="center" class="matrix-form-controls" width="99%">
<tr>
<td>
<div style="height:auto;width:16px;float:right;margin-top:4px;">
<div id="btnbedit" onclick="EditBasicDetails()" title="edit basic details" style="background:url('/matrix/images/edit_form.png');height:auto;width:16px;cursor:pointer;margin-top:2px">&nbsp;</div>
<div id="btnbsave" onclick="SaveBasicDetails()" title="save details" style="background:url('/matrix/images/disk.png');height:auto;width:16px;cursor:pointer;margin-top:2px">&nbsp;</div>
<div id="btnbcancel" onclick="CancelEdit()" title="cancel" style="background:url('/matrix/images/msgerror.png');height:auto;width:16px;cursor:pointer;margin-top:6px">&nbsp;</div>
</div>
<div class="widget">
<div class="lblcontainer">
Appl No.
</div>
<div class="inputcontainer">
<input type="text" id="applno" name="applno" maxlength="25" style="width:150px;text-transform:uppercase" value="" disabled="disabled" onblur="if(validate(this,'t','AlphaNumeric')){FindSameDet(this,'A','customername');}" />
</div>
</div>
<div class="widget">
<div class="lblcontainer">
Name
</div>
<div class="inputcontainer">
<input type="text" id="customername" name="customername" maxlength="100" style="width:275px" value="" onblur="validate(this,'t','AlphaSpace');" disabled="disabled" />
</div>
</div>
<div class="widget">
<div class="lblcontainer">
DOB
</div>
<div class="inputcontainer">
<input type="text" id="dob" name="dob" maxlength="10" style="width:80px" value="" onkeydown="return addSlashes(this,event)" onblur="validate(this,'f','Date')" disabled="disabled" />
</div>
</div>
<div class="widget">
<div class="lblcontainer">
Loan Amt
</div>
<div class="inputcontainer">
<input type="text" id="loanamount" name="loanamount" maxlength="15" style="width:115px" value="" onblur="validate(this,'f','LoanAmount');" disabled="disabled" />
</div>
</div>
<div class="widget">
<div class="lblcontainer">
Branch
</div>
<div class="inputcontainer">
<div class="divselect" id="divbranch" style="width:235px;">
<select id="bank_branch_id" name="bank_branch_id" style="width:253px" onblur="validate(this,'t','');" disabled="disabled">
<option value="-1" selected >SELECT</option>
<c:forEach items="${branchlist}" var="brnch">
<option value="${brnch[0]}">${brnch[1]}</option>
</c:forEach>
</select>
</div>
</div>
</div>
<div class="widget">
<div class="lblcontainer">
Product
</div>
<div class="inputcontainer">
<div class="divselect" id="divproduct" style="width:132px;">
<select id="product" name="product" style="width:150px" onblur="validate(this,'t','');" disabled="disabled">
<option value="-1" selected >SELECT</option>
<c:forEach items="${prodlist}" var="prod">
<option value="${prod[0]}">${prod[1]}</option>
</c:forEach>
</select>
</div>
</div>
</div>
<div class="widget">
<div class="lblcontainer">
App Type
</div>
<div class="inputcontainer">
<div class="divselect" id="divapptype" style="width:135px;">
<select id="apptype" name="apptype" style="width:153px" onblur="validate(this,'t','');" disabled="disabled">
<option value="-1" selected>SELECT</option>
<c:forEach items="${typelist}" var="type">
<option value="${type[0]}">${type[1]}</option>
</c:forEach>
</select>
</div>
</div>
</div>
<div class="widget">
<div class="lblcontainer">
Category
</div>
<div class="inputcontainer">
<div class="divselect" id="divcategory" style="width:115px;">
<select id="category" name="category" style="width:133px" disabled="disabled">
<option value="-1" selected>SELECT</option>
<c:forEach items="${catlist}" var="cat">
<option value="${cat[0]}">${cat[1]}</option>
</c:forEach>
</select>
</div>
</div>
</div>
${dynamichtml}
<input type="button" class="button" name="btnsave" style="float:right" value="Add Docs" id="btnsave" onclick="return AddDocs();" />
</td>
</tr>
</table>
</div>
<!-- -->
</div>
<!-- -->
<!-- Document Details Visible for portfolios in which document verification could be done-->
<div id="section7">
<!-- Title -->
<div class="title">
<img class="matrix-title-icon" src="/matrix/images/documents.png" />
<span class="matrix-title-text">Document Details</span>
</div>
<!-- -->
<!-- Form (Section1) -->
<div id="FormPanel1" class="FormPanel">
<table align="center" class="matrix-form-controls" width="99%">
<tr>
<td>
<div class="widget">
<div class="lblcontainer">
Document
</div>
<div class="inputcontainer">
<div class="divselect" id="divdoctype" style="width:170px;">
<select id="doctype" name="doctype" style="width:188px" onchange="changeLabel(this)" onblur="validate(this,'t','')">
<option value="-1" uniqueidentifier="Unique No." sprovider="Service Provider" validuno="xxx" ymon="A.Y/Month" validymon="" defsprovider="" genlist="0" selected>SELECT</option>
<c:forEach items="${doclist}" var="doc">
<option value="${doc[0]}" uniqueidentifier="${doc[2]}" sprovider="${doc[3]}" validuno="${doc[4]}" ymon="${doc[5]}" validymon="${doc[6]}" defsprovider="${doc[7]}" genlist="${doc[8]}">${doc[1]}</option>
</c:forEach>
</select>
</div>
</div>
</div>
<div class="widget">
<div class="lblcontainer">
Name
</div>
<div class="inputcontainer">
<input type="text" id="docholdername" name="docholdername" maxlength="100" style="width:200px" value="" onblur="validate(this,'t','AlphaSpace');" />
</div>
</div>
<div class="widget">
<div class="lblcontainer" id="sprovider">
Serivce Provider
</div>
<div class="inputcontainer">
<input type="text" id="serviceprovider" name="serviceprovider" maxlength="100" style="width:200px" value="" onblur="validate(this,'t','SplInstruction');" />
<input type="hidden" id="bank_id" name="serviceprovider_hidden" value="0" />
<input type="hidden" id="serviceprovider_citylist" name="serviceprovider_citylist" value="0" />
</div>
</div>
<div class="widget">
<div class="lblcontainer" id="uniqueidentifier">
Unique No.
</div>
<div class="inputcontainer">
<input type="text" id="uniqueno" name="uniqueno" maxlength="50" style="width:140px" value="" />
</div>
</div>
<div class="widget">
<div class="lblcontainer" id="yearmon">
A.Y/Month
</div>
<div class="inputcontainer">
<input type="text" id="yearmonth" name="yearmonth" maxlength="100" style="width:180px" value="" />
</div>
</div>
<div class="widget">
<div class="lblcontainer">
Location
</div>
<div class="inputcontainer">
<div class="divselect" id="divcity" style="width:120px;" >
<select id="city" name="city" style="width:138px" onblur="validate(this,'t','');">
<option value="-1" selected>SELECT</option>
<option value="CITY" selected>CITY</option>
<option value="SATELLITE CITY">SATELLITE CITY</option>
<option value="OUT STATION">OUT STATION</option>
</select>
</div>
</div>
</div>
<div class="widget">
<div class="lblcontainer">
Vendor
</div>
<div class="inputcontainer">
<div class="divselect" id="divvendor" style="width:120px;">
<select id="vendor_id" name="vendor_id" style="width:138px" onblur="validate(this,'f','');">
<option value="-1" selected>SELECT</option>
</select>
</div>
</div>
</div>
${docdynamichtml}
<input type="button" class="button" name="btnadd" style="float:right" value="Add" id="btnadd" onclick="return AddNewDoc();" />
</td>
</tr>
</table>
</div>
<div id="FormPanel2" class="FormPanel">
<table border="0" cellspacing="0" width="100%" id="casetable">
<thead class="thead">
<tr title="Row Title" id="rowtitle">
<td style="font-size:12px;width:20px">S.No</td>
<td style="font-size:12px;width:150px">Name</td>
<td style="font-size:12px;width:150px">Document</td>
<td style="font-size:12px;width:150px">Provider</td>
<td style="font-size:12px;width:150px">Unique No.</td>
<td style="font-size:12px;width:100px">Extra</td>
<td style="font-size:12px;width:50px">Location</td>
<td style="font-size:12px;width:50px">Vendor</td>
<td style="font-size:12px">Action</td>
</tr>
</thead>
</table>
</div>
<!-- -->
</div>
<input type="hidden" id="dynamicfields" name="dynamicfields" value="${dynamicfields}" />
<input type="hidden" id="docdynamicfields" name="dynamicfields" value="${docdynamicfields}" />
<input type="hidden" id="uuid" name="uuid" value="" />
<input type="hidden" id="case_id" name="case_id" value="" />
<input type="hidden" id="company_id" name="company_id" value="${Sessvals.getCompanyID()}" />
<input type="hidden" id="branch_id" name="branch_id" value="${Sessvals.getBranchID()}" />
<input type="hidden" id="status" name="status" value="" />
<input type="hidden" id="docv" name="docv" value="0" />
<!-- -->
<input type="hidden" id="invalidfields" value="0" />
<c:if test="${formmode gt 0}">
<div style="position:fixed;text-align:right;bottom:0px;width:980px;" class="buttonbar">
<input type="hidden" id="invalidfields" value="0" />
<input type="button" class="button" name="btnfirst" style="margin-left:5px;margin-top:-2px;float:left;width:80px" value="" id="btnfirst" accesskey="F" onclick="findRecord(1)" />
<input type="button" class="button" name="btnprev" style="margin-top:-2px;float:left;width:80px" value="" id="btnprev" accesskey="P" onclick="findRecord(2)" />
<input type="button" class="button" name="btnnext" style="margin-top:-2px;float:left;width:80px" value="" id="btnnext" accesskey="N" onclick="findRecord(3)" />
<input type="button" class="button" name="btnlast" style="margin-top:-2px;float:left;width:80px" value="" id="btnlast" accesskey="L" onclick="findRecord(4)" />
<input type="button" class="button" name="btnadd" style="float:right" value="Add New Record" id="btnadd" accesskey="A" onclick="return AddNewRecord();" />
</div>
</c:if>
</form>
<input type="hidden" id="formmode" name="formmode" value="${formmode}" />
<input type="hidden" id="usid" name="usid" value="${usid}" />
</div>
</div>
</body>
<!-- Page Load Javascript -->
<script language="javascript" type="text/javascript">
InitPage('${portfolio_id}');
</script>
<!-- -->
<!-- Process Message -->
<c:if test="${not empty msg}">
<script language="javascript" type="text/javascript"> CallMessage('${msg}',3000,200,300); </script>
</c:if>
<!-- -->
</html>

View File

@@ -1,29 +1,67 @@
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!doctype html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<script language="javascript" src="/matrix/js/lib/constants.js" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/lib/jsfuncs.js" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/jquery1.7.2.js" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/ui/uifuncs.js" type="text/javascript"></script>
<script language="javascript" src="/matrix/js/validator.js" type="text/javascript"></script>
<link href="/matrix/css/matrix.css" rel="stylesheet" type="text/css" />
<link href="/matrix/css/div.css" rel="stylesheet" type="text/css" />
<title>Cygnus 1.0 | 404 Error</title>
<script src="/matrix/js/matrix-accessibility-v1.js?v=1" defer></script>
<link href="/matrix/css/matrix-theme-v2.css?v=4" rel="stylesheet" type="text/css" />
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="<c:url value='/css/bootstrap-5.3.8.min.css' />" rel="stylesheet" />
<link href="<c:url value='/css/matrix-v2.css' />" rel="stylesheet" />
<link href="<c:url value='/css/matrix-shell-v2.css' />" rel="stylesheet" />
<link href="<c:url value='/css/matrix-theme-v2.css' />" rel="stylesheet" />
<script src="<c:url value='/js/matrix-shell-v2.js' />" defer></script>
<title>Cygnus 1.0 | <c:out value="${empty messageDetails.title ? 'Page unavailable' : messageDetails.title}" /></title>
</head>
<body class="matrix-error-page">
<form method="post" name="unaccess" id="unaccess">
<main class="matrix-error-card" role="alert" aria-labelledby="errorTitle">
<div class="matrix-error-card__code">404</div>
<h1 id="errorTitle">Page unavailable</h1>
<p>Unauthorized access or the requested page could not be found.</p>
<button type="button" class="matrix-error-card__action" onclick="SubmitForm('logout', '_parent', 'unaccess');">Return to sign in</button>
<body class="matrix-v2 matrix-shell matrix-error-page matrix-error-page--${empty messageDetails.httpStatus ? 404 : messageDetails.httpStatus}">
<c:choose>
<c:when test="${not empty Sessvals and not empty Sessvals.menuHtml}">
<%@ include file="/WEB-INF/app/fragments/app-shell-header.jspf" %>
</c:when>
<c:otherwise>
<%@ include file="/WEB-INF/app/fragments/app-title.jspf" %>
</c:otherwise>
</c:choose>
<main class="matrix-error-layout" id="mainContent">
<section class="matrix-error-card" role="alert" aria-labelledby="errorTitle">
<div class="matrix-error-card__status" aria-hidden="true">
<span><c:out value="${empty messageDetails.httpStatus ? 404 : messageDetails.httpStatus}" /></span>
</div>
<div class="matrix-error-card__content">
<span class="matrix-error-card__eyebrow">
Error <c:out value="${empty messageDetails.code ? 'HTTP-404' : messageDetails.code}" />
</span>
<h1 id="errorTitle">
<c:out value="${empty messageDetails.title ? 'Page unavailable' : messageDetails.title}" />
</h1>
<p class="matrix-error-card__message">
<c:out value="${empty messageDetails.message ? 'The requested page is unavailable.' : messageDetails.message}" />
</p>
<c:if test="${not empty messageDetails.description}">
<p class="matrix-error-card__description"><c:out value="${messageDetails.description}" /></p>
</c:if>
<div class="matrix-error-card__actions">
<c:choose>
<c:when test="${not empty Sessvals and not empty Sessvals.menuHtml}">
<form method="post" action="<c:url value='/ver/dashboard' />">
<button type="submit" class="matrix-error-card__action">Return to dashboard</button>
</form>
<button type="button" class="matrix-error-card__action matrix-error-card__action--secondary" onclick="history.back()">Go back</button>
</c:when>
<c:otherwise>
<a class="matrix-error-card__action" href="<c:url value='/ver/login' />">Return to sign in</a>
</c:otherwise>
</c:choose>
</div>
<c:if test="${not empty messageDetails.referenceId}">
<p class="matrix-error-card__reference">
Reference ID: <code><c:out value="${messageDetails.referenceId}" /></code>
</p>
</c:if>
</div>
</section>
</main>
</form>
</body>
</html>

View File

@@ -6,8 +6,8 @@
<span>Cygnus 1.0</span>
</div>
<div class="matrix-shell__context" aria-label="Current session">
<span class="matrix-shell__company"><c:out value="${Sessvals.getCompanyCode()}" /> (<c:out value="${Sessvals.getBranchLocation()}" />)</span>
<span class="matrix-shell__user"><c:out value="${Sessvals.getUserDisplayName()}" /> (<c:out value="${Sessvals.getUserGroupName()}" />)</span>
<span class="matrix-shell__company"><c:out value="${sessionScope.userSession.companyCode}" /> (<c:out value="${sessionScope.userSession.branchLocation}" />)</span>
<span class="matrix-shell__user"><c:out value="${sessionScope.userSession.userDisplayName}" /> (<c:out value="${sessionScope.userSession.userGroupName}" />)</span>
</div>
</div>
</header>

View File

@@ -38,6 +38,14 @@
</session-config>
<!-- Error Page -->
<error-page>
<error-code>404</error-code>
<location>/ver/error</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/ver/error</location>
</error-page>
<error-page>
<exception-type>org.springframework.web.HttpSessionRequiredException</exception-type>
<location>/matrix/index.jsp</location>

View File

@@ -31,6 +31,12 @@
margin: 0;
}
/* Legacy forms separate labels and controls with a BR. In the modern flex
layout that BR becomes an extra flex row and creates an unintended gap. */
.matrix-add-cases .matrix-form-controls .widget > br {
display: none;
}
.matrix-add-cases .matrix-form-controls .widget[style*="display:none"] {
display: none !important;
}
@@ -57,6 +63,41 @@
.matrix-add-cases .matrix-form-controls textarea {
width: 100% !important;
min-height: 30px;
font-weight: 400;
}
.matrix-add-cases .matrix-phone-extension {
display: grid;
grid-template-columns: minmax(0, 1fr) auto 48px;
align-items: center;
gap: 4px;
}
.matrix-add-cases .matrix-phone-extension > input {
width: 100% !important;
min-width: 0;
}
.matrix-add-cases .matrix-edit-back {
display: inline-flex;
align-items: center;
gap: 5px;
min-height: 28px;
margin-left: auto;
padding: 3px 10px;
color: #245f91;
font-size: 12px;
font-weight: 600;
border: 1px solid #9eb5c8;
border-radius: 4px;
background: #f6f9fb;
}
.matrix-add-cases .matrix-edit-back:hover,
.matrix-add-cases .matrix-edit-back:focus-visible {
color: #fff;
border-color: #28699d;
background: #28699d;
}
.matrix-add-cases .matrix-form-controls .widget:has(#splist),
@@ -89,3 +130,87 @@
.matrix-add-cases .matrix-form-controls .widget:has(#splist),
.matrix-add-cases .matrix-form-controls .widget:has(textarea) { grid-column: span 6; }
}
.matrix-add-cases .inputcontainer {
position: relative;
}
.matrix-add-cases .inputcontainer > input.errtxt,
.matrix-add-cases .inputcontainer > textarea.errtxt {
padding-right: 24px !important;
}
.matrix-add-cases .matrix-validation-error-icon {
display: block;
margin: 0 !important;
object-fit: contain;
}
.matrix-add-cases #section2 > .title,
.matrix-add-cases #section3 > .title,
.matrix-add-cases #section4 > .title,
.matrix-add-cases #section5 > .title,
.matrix-add-cases #section6 > .title,
.matrix-add-cases #section7 > .title {
box-sizing: border-box;
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 6px 8px;
min-height: 38px;
height: auto !important;
padding: 5px 10px !important;
}
.matrix-add-cases #section2 > .title > .matrix-title-icon,
.matrix-add-cases #section3 > .title > .matrix-title-icon,
.matrix-add-cases #section4 > .title > .matrix-title-icon,
.matrix-add-cases #section5 > .title > .matrix-title-icon,
.matrix-add-cases #section6 > .title > .matrix-title-icon,
.matrix-add-cases #section7 > .title > .matrix-title-icon {
display: block;
flex: 0 0 16px;
width: 16px;
height: 16px;
margin: 0 !important;
object-fit: contain;
vertical-align: middle;
}
.matrix-add-cases #section2 > .title > .matrix-title-text,
.matrix-add-cases #section3 > .title > .matrix-title-text,
.matrix-add-cases #section4 > .title > .matrix-title-text,
.matrix-add-cases #section5 > .title > .matrix-title-text,
.matrix-add-cases #section6 > .title > .matrix-title-text,
.matrix-add-cases #section7 > .title > .matrix-title-text {
line-height: 16px;
}
.matrix-add-cases #section2 > .title > .divchk,
.matrix-add-cases #section3 > .title > .divchk,
.matrix-add-cases #section4 > .title > .divchk,
.matrix-add-cases #section5 > .title > .divchk,
.matrix-add-cases #section7 > .title > .divchk {
position: static !important;
right: auto !important;
float: none !important;
display: inline-flex;
align-items: center;
align-self: center;
gap: 4px;
min-height: 18px;
margin: 0 0 0 auto !important;
padding: 0 !important;
line-height: 18px !important;
white-space: nowrap;
}
.matrix-add-cases #section2 > .title > .divchk input[type="checkbox"],
.matrix-add-cases #section3 > .title > .divchk input[type="checkbox"],
.matrix-add-cases #section4 > .title > .divchk input[type="checkbox"],
.matrix-add-cases #section5 > .title > .divchk input[type="checkbox"],
.matrix-add-cases #section7 > .title > .divchk input[type="checkbox"] {
flex: 0 0 auto;
margin-top: 0 !important;
margin-bottom: 0 !important;
vertical-align: middle;
}

View File

@@ -75,7 +75,8 @@
right:8px;
cursor:pointer;
}
.title #ctrldiv
.title #ctrldiv,
.title .ctrldiv
{
border:none;
position:relative;

View File

@@ -4,19 +4,66 @@
background: #f4f8fb;
}
.matrix-edit-cases .matrix-tool-workspace__content > .title .divselect {
width: min(330px, 38vw) !important;
margin-left: auto;
position: static !important;
.matrix-edit-cases #caseGrid > div > .title {
display: flex !important;
align-items: center;
flex-wrap: nowrap !important;
gap: 7px;
}
.matrix-edit-cases .matrix-tool-workspace__content > .title select {
width: 100% !important;
min-height: 28px;
padding: 3px 28px 3px 7px;
border: 1px solid #9fb1c1;
border-radius: 3px;
background-color: #fff;
.matrix-edit-cases #caseGrid > div > .title > .matrix-title-text {
flex: 0 0 auto;
white-space: nowrap;
}
.matrix-edit-cases #caseGrid > div > .title > .matrix-edit-cases__portfolio-select {
width: 0 !important;
min-width: 0;
flex: 1 1 auto;
margin: 0 !important;
font-family: Tahoma, Arial, sans-serif;
font-size: 10pt;
font-weight: 400;
padding: 2px 30px 2px 7px !important;
}
.matrix-edit-cases #caseGrid > div > .title > .matrix-edit-cases__refresh {
box-sizing: border-box !important;
width: 27px !important;
height: 27px !important;
min-width: 27px !important;
min-height: 27px !important;
margin: 0 !important;
flex: 0 0 27px;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0 !important;
border: 0 !important;
border-radius: 0 !important;
outline: 0 !important;
appearance: none;
background: transparent !important;
box-shadow: none !important;
}
.matrix-edit-cases #caseGrid > div > .title > .matrix-edit-cases__refresh:hover,
.matrix-edit-cases #caseGrid > div > .title > .matrix-edit-cases__refresh:focus,
.matrix-edit-cases #caseGrid > div > .title > .matrix-edit-cases__refresh:focus-visible,
.matrix-edit-cases #caseGrid > div > .title > .matrix-edit-cases__refresh:active {
width: 27px !important;
height: 27px !important;
margin: 0 !important;
padding: 0 !important;
border: 0 !important;
outline: 0 !important;
background: transparent !important;
box-shadow: none !important;
}
.matrix-edit-cases .matrix-edit-cases__refresh img {
width: 16px;
height: 16px;
}
.matrix-edit-cases .tableContainer {
@@ -55,12 +102,4 @@
width: 100% !important;
}
.matrix-edit-cases .matrix-tool-workspace__content > .title {
flex-wrap: wrap;
}
.matrix-edit-cases .matrix-tool-workspace__content > .title .divselect {
width: 100% !important;
order: 3;
}
}

View File

@@ -119,45 +119,103 @@ body .nav-menu {
}
body.matrix-error-page {
display: grid;
min-height: 100vh;
margin: 0;
padding: 24px;
place-items: center;
color: #263746;
background: var(--matrix-theme-canvas) !important;
font-family: Arial, sans-serif;
}
.matrix-error-card {
width: min(100%, 480px);
.matrix-error-layout {
min-height: calc(100vh - 84px);
display: grid;
place-items: center;
box-sizing: border-box;
padding: clamp(24px, 5vw, 64px) 20px;
}
.matrix-error-card {
width: min(100%, 760px);
display: grid;
grid-template-columns: 150px minmax(0, 1fr);
overflow: hidden;
box-sizing: border-box;
padding: 30px;
text-align: center;
border: 1px solid var(--matrix-theme-border);
border-radius: 8px;
border-radius: 10px;
background: var(--matrix-theme-panel);
box-shadow: 0 8px 24px rgba(31, 52, 72, .12);
}
.matrix-error-card__code {
color: #b42318;
font-size: 38px;
.matrix-error-card__status {
min-height: 290px;
display: grid;
place-items: center;
color: #fff;
background: #a4473f;
}
.matrix-error-page--401 .matrix-error-card__status,
.matrix-error-page--403 .matrix-error-card__status {
background: #a66a19;
}
.matrix-error-page--404 .matrix-error-card__status,
.matrix-error-page--405 .matrix-error-card__status {
background: #376b94;
}
.matrix-error-card__status span {
font-size: 42px;
font-weight: 800;
line-height: 1;
}
.matrix-error-card h1 {
margin: 10px 0 6px;
font-size: 21px;
.matrix-error-card__content {
padding: 34px 38px 28px;
}
.matrix-error-card p {
margin: 0 0 20px;
.matrix-error-card__eyebrow {
color: #607587;
font-size: 12px;
font-weight: 700;
letter-spacing: .08em;
text-transform: uppercase;
}
.matrix-error-card h1 {
margin: 8px 0 10px;
font-size: 25px;
}
.matrix-error-card__message {
margin: 0 0 8px;
color: #344b5e;
font-size: 15px;
font-weight: 600;
}
.matrix-error-card__description {
margin: 0;
color: #536779;
line-height: 1.55;
}
.matrix-error-card__actions {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 9px;
margin-top: 24px;
}
.matrix-error-card__actions form {
margin: 0;
}
.matrix-error-card__action {
display: inline-flex;
align-items: center;
justify-content: center;
min-height: 34px;
padding: 6px 16px;
color: #fff;
@@ -166,6 +224,55 @@ body.matrix-error-page {
background: #245a91;
font-weight: 700;
cursor: pointer;
text-decoration: none;
}
.matrix-error-card__action:hover,
.matrix-error-card__action:focus {
color: #fff;
background: #1d4e7d;
}
.matrix-error-card__action--secondary {
color: #334b5e;
border-color: #aebdca;
background: transparent;
}
.matrix-error-card__action--secondary:hover,
.matrix-error-card__action--secondary:focus {
color: #263746;
background: #e4edf4;
}
.matrix-error-card__reference {
margin: 22px 0 0;
padding-top: 14px;
color: #6b7e8e;
border-top: 1px solid #d5e0e8;
font-size: 11px;
}
.matrix-error-card__reference code {
color: inherit;
}
@media (max-width: 620px) {
.matrix-error-card {
grid-template-columns: 1fr;
}
.matrix-error-card__status {
min-height: 82px;
}
.matrix-error-card__status span {
font-size: 30px;
}
.matrix-error-card__content {
padding: 26px 24px;
}
}
/* Compact toolbars for legacy forms that place controls in their title bar. */

View File

@@ -123,6 +123,22 @@ body.matrix-v2 #PageFrame {
border-radius: var(--matrix-radius-sm);
}
.matrix-v2 #cygnus-notifications .alert-dismissible {
position: relative;
padding-right: 38px;
}
.matrix-v2 #cygnus-notifications .alert-dismissible > .btn-close {
position: absolute;
top: 50%;
right: 10px;
width: 1em;
height: 1em;
margin: 0;
padding: 0;
transform: translateY(-50%);
}
/* Shared title treatment for migrated and legacy-backed views. */
.matrix-v2 .title,
.matrix-v2 .card-header,

View File

@@ -53,11 +53,14 @@
min-width: 72px;
}
.matrix-punch-workspace .buttonbar input[id="btnsave"],
.matrix-punch-workspace .buttonbar input[id="btnadd"] {
.matrix-punch-workspace .buttonbar input[id="btnsave"] {
margin-left: auto !important;
}
.matrix-punch-workspace .buttonbar input[id="btnadd"] {
margin-left: 0 !important;
}
.matrix-punch-workspace #formcontainer > .title {
position: sticky;
z-index: 21;

View File

@@ -31,7 +31,6 @@ Owner of DHTMLgoodies.com
var ajax_list_externalFile = 'getlocality'; // Path to external file
var minimumLettersBeforeLookup = 1; // Number of letters entered before a lookup is performed.
var ajax_list_objects = new Array();
var ajax_list_cachedLists = new Array();
var ajax_list_activeInput = false;
var ajax_list_activeItem;
@@ -75,19 +74,13 @@ Owner of DHTMLgoodies.com
ajax_list_activeInput.value = tmpValue;
if(document.getElementsByName(ajax_list_activeInput.name + '_hidden')[0])
{
document.getElementsByName(ajax_list_activeInput.name + '_hidden')[0].value = inputObj.id.split("#-#")[0];
document.getElementsByName(ajax_list_activeInput.name + '_hidden')[0].value = inputObj.dataset.localityId;
if(ajax_list_externalFile == 'getlocality')
{
document.getElementsByName(ajax_list_activeInput.name + '_pincode')[0].value = inputObj.id.split("#-#")[1];
document.getElementsByName(ajax_list_activeInput.name + '_citylist')[0].value = inputObj.id.split("#-#")[2];
document.getElementsByName(ajax_list_activeInput.name + '_pincode')[0].value = inputObj.dataset.pincode;
document.getElementsByName(ajax_list_activeInput.name + '_citylist')[0].value = inputObj.dataset.city;
}
//$('#'+ajax_list_activeInput.name + '_pincode').val(inputObj.id.split("#-#")[1]);
//$('#'+ajax_list_activeInput.name + '_citylist').val(inputObj.id.split("#-#")[2]);
}
//var f1=setTimeout('ajax_list_activeInput.focus()',1);
//var f2=setTimeout('ajax_list_activeInput.value = ajax_list_activeInput.value',1);
ajax_options_hide();
}
@@ -119,7 +112,7 @@ Owner of DHTMLgoodies.com
ajax_optionDiv.innerHTML = '';
ajax_list_activeItem = false;
if(ajax_list_cachedLists[paramToExternalFile][letters.toLowerCase()].length<=1){
if(ajax_list_cachedLists[paramToExternalFile][letters.toLowerCase()].length===0){
ajax_options_hide();
return;
}
@@ -129,19 +122,20 @@ Owner of DHTMLgoodies.com
ajax_list_optionDivFirstItem = false;
var optionsAdded = false;
for(var no=0;no<ajax_list_cachedLists[paramToExternalFile][letters.toLowerCase()].length;no++){
if(ajax_list_cachedLists[paramToExternalFile][letters.toLowerCase()][no].length==0)continue;
var locality = ajax_list_cachedLists[paramToExternalFile][letters.toLowerCase()][no];
if(!locality || !locality.location)continue;
optionsAdded = true;
var div = document.createElement('DIV');
var items = ajax_list_cachedLists[paramToExternalFile][letters.toLowerCase()][no].split(/!C0L!/gi);
if(ajax_list_cachedLists[paramToExternalFile][letters.toLowerCase()].length==1 && ajax_list_activeInput.value == items[0]){
if(ajax_list_cachedLists[paramToExternalFile][letters.toLowerCase()].length==1 && ajax_list_activeInput.value == locality.location){
ajax_options_hide();
return;
}
div.innerHTML = items[items.length-1];
div.id = items[0];
div.textContent = locality.location;
div.dataset.localityId = locality.id;
div.dataset.pincode = locality.pincode || '';
div.dataset.city = locality.city || '';
div.className='optionDiv';
div.onmouseover = function(){ ajax_options_rollOverActiveItem(this,false); };
div.onclick = ajax_option_setValue;
@@ -156,17 +150,6 @@ Owner of DHTMLgoodies.com
}
function ajax_option_list_showContent(ajaxIndex,inputObj,paramToExternalFile,whichIndex)
{
if(whichIndex!=currentListIndex)return;
var letters = inputObj.value;
var content = ajax_list_objects[ajaxIndex].response;
var elements = content.split('!R0W!');
ajax_list_cachedLists[paramToExternalFile][letters.toLowerCase()] = elements;
ajax_option_list_buildList(letters,paramToExternalFile);
}
function ajax_option_resize(inputObj)
{
ajax_optionDiv.style.top = (ajax_getTopPos(inputObj) + inputObj.offsetHeight + ajaxBox_offsetY) + 'px';
@@ -252,16 +235,25 @@ Owner of DHTMLgoodies.com
}else{
var tmpIndex=currentListIndex/1;
ajax_optionDiv.innerHTML = '';
var ajaxIndex = ajax_list_objects.length;
ajax_list_objects[ajaxIndex] = new sack();
if(cityval.toUpperCase() == "GURGAON") {
cityval = "Gurugram";
}
//var url = ajax_list_externalFile + '?' + paramToExternalFile + '='+cityval+'&letters=' + inputObj.value.replace(" ","+");
var url = ajax_list_externalFile + '?city='+cityval+'&letters=' + inputObj.value.replace(" ","+");
ajax_list_objects[ajaxIndex].requestFile = url; // Specifying which file to get
ajax_list_objects[ajaxIndex].onCompletion = function(){ ajax_option_list_showContent(ajaxIndex,inputObj,paramToExternalFile,tmpIndex); }; // Specify function that will be executed after file has been found
ajax_list_objects[ajaxIndex].runAJAX(); // Execute AJAX function
var letters=inputObj.value;
var url=ajax_list_externalFile+'?'+new URLSearchParams({city:cityval,letters:letters}).toString();
fetch(url,{method:'GET',credentials:'same-origin',headers:{Accept:'application/json'}})
.then(function(response){return response.json().then(function(body){return {response:response,body:body};});})
.then(function(result){
if(!result.response.ok || !result.body || !result.body.success) throw result.body && result.body.message ? result.body.message : {};
var localities=Array.isArray(result.body.data && result.body.data.localities) ? result.body.data.localities : [];
ajax_list_cachedLists[paramToExternalFile][letters.toLowerCase()]=localities;
if(tmpIndex==currentListIndex) ajax_option_list_buildList(letters,paramToExternalFile);
})
.catch(function(error){
if(tmpIndex!=currentListIndex)return;
ajax_options_hide();
CygnusNotifications.show({type:'danger',code:error.code || 'APP-5002',
message:error.message || 'Cygnus could not load localities.',referenceId:error.referenceId});
});
}

View File

@@ -1,120 +0,0 @@
var currow=null;
function ValidateEntry(flag)
{
validate(document.getElementById("doctype"),flag,'');
validate(document.getElementById("docholdername"),flag,'SplInstruction');
if(validateHidden && $("#serviceprovider_hidden").val()=='')
{
$("#serviceprovider").val('');
}
validate(document.getElementById("serviceprovider"),flag,'SplInstruction');
var temp=$("#uniqueno").attr("onblur").replace( "validate(","" ).replace( ")","").replace(/'/g,"").split(",");
validate(document.getElementById("uniqueno"),flag,temp[2]);
var temp=$("#yearmonth").attr("onblur").replace( "validate(","" ).replace( ")","").replace(/'/g,"").split(",");
validate(document.getElementById("yearmonth"),temp[1],temp[2]);
validate(document.getElementById("city"),flag,'');
}
function AddNewDoc()
{
ValidateEntry('t');
if(checkForm())
{
UpdateDoc();
}
else
{
CallMessage('VLFRM:error:There are one or more error(s) in form. Please correct them and try again.',3000,200,300);
}
}
function AddDocRow(data,did,vname)
{
var tbody = $('#doclist');
var totdocs= $('#doclist tr').length;
var row = null;
if(data.doc_id=='0')
{
row = $('<tr></tr>').attr("did",did).attr("onclick","GetRowData(this)").appendTo(tbody);
}
else
{
if(currow != null)
{
row = $("#doclist tr:eq("+currow+")");
$(row).html('');
totdocs = currow;
}
}
$('<td></td>').text(totdocs+1).appendTo(row);
$('<td></td>').text(data.docholdername).appendTo(row);
$('<td></td>').attr("dtype",data.doctype).text($("#doctype option[value='"+data.doctype+"']").text()).appendTo(row);
$('<td></td>').attr("id",data.serviceprovider_hidden).text(data.serviceprovider).appendTo(row);
$('<td></td>').attr("title",data.city).text(data.uniqueno).appendTo(row);
$('<td></td>').text(data.yearmonth).appendTo(row);
$('<td></td>').attr("id",data.vendor_id).text((vname.length > 0 ? vname:$("#vendor_id option[value='"+data.vendor_id+"']").text())).appendTo(row);
$('<td></td>').text("").appendTo(row);
}
function GetRowData(drow)
{
currow = $(drow).index();
$("#doctype").val($(drow).find('td').eq(2).attr("dtype"));
$("#doctype").trigger("change");
$("#docholdername").val($(drow).find('td').eq(1).text().trim());
$("#serviceprovider").val($(drow).find('td').eq(3).text().trim());
$("#serviceprovider_hidden").val($(drow).find('td').eq(3).attr("id"));
$("#uniqueno").val($(drow).find('td').eq(4).text().trim());
$("#yearmonth").val($(drow).find('td').eq(5).text().trim());
$("#city").val($(drow).find('td').eq(4).attr("title").trim());
//$("#vendor_id").val($(drow).find('td').eq(6).attr("id"));
ValidateEntry('t');
$("#doc_id").val($(drow).attr("did"));
}
function resetDocForm()
{
validateHidden = false;
document.getElementById('docdetails').reset();
$('#city').val("-1");
$('#vendor_id').empty().append('<option value="-1" selected>SELECT</option>');
currow = null;
}
function UpdateDoc()
{
var jsonString = JSON.stringify($('#docdetails').serializeObject()).substring();
jsonString = '{'+jsonString.substring(1, jsonString.length-1)+',"uuid":"'+$("#uuid").val()+'","usid":"'+$("#usid").val()+'"}';
$.ajax({
url:"doc/updcasedocs",
type:"POST",
contentType: "application/json; charset=utf-8",
data: jsonString, //Stringified Json Object
async: false, //Cross-domain requests and dataType: "jsonp" requests do not support synchronous operation
cache: false, //This will force requested pages not to be cached by the browser
processData:false, //To avoid making query String instead of JSON
success: function(resposeJsonObject){
var dataArray = jQuery.parseJSON(resposeJsonObject);
if(dataArray.status.search("error") > -1)
{
CallMessage(dataArray.result,3000,200,300);
}
else
{
AddDocRow(dataArray.result,dataArray.did,'');
resetDocForm();
}
}
});
}
$.fn.serializeObject = function()
{
var o = {};
var a = this.serializeArray();
$.each(a, function() {
if (o[this.name] !== undefined) {
if (!o[this.name].push) {
o[this.name] = [o[this.name]];
}
o[this.name].push(this.value || '');
} else {
o[this.name] = this.value || '';
}
});
return o;
};

View File

@@ -1,68 +0,0 @@
var currow=0;
var lastrow=0;
function InitPage()
{
$('form tbody.scrollContent tr').hover(function () {
$('#row'+lastrow).removeClass('rowhover');
ResetRow();
$(this).addClass('rowhover');
}, function () {
$(this).removeClass('rowhover');
});
$('form tbody.scrollContent tr').click(function () {
GetRowData(this);
});
}
function ResetRow()
{
currow=0;
lastrow=$('#casetable tr').length-1;
}
function GetRowData(SelectedRow)
{
/*QueryStr="rand="+Math.round(Math.random()*4+1)+"&uuid="+$("#"+SelectedRow.id+"uuid").val()+"&pid="+$("#"+SelectedRow.id+"portid").val();
var retVal=0; // Legacy commented example retained without removed browser API.
if(retVal==1)
{
$("#"+SelectedRow.id+"col").html("<img src='/matrix/images/edited.png' title='Details has been edited successfully. Please click refresh button to see the changes' />");
}*/
$("#uuid").val($("#"+SelectedRow.id+"uuid").val());
SubmitForm("caseedit", "_blank", "caseGrid");
}
function keyListen(param1,param2,e) {
var keycode = e.keyCode;
if(keycode==13)
{
GetRowData(document.getElementById("row"+currow));
}
else
{
if(keycode==40)
{
currow=currow+1;
if(currow>=$('#casetable tr').length){currow=1;lastrow=$('#casetable tr').length-1;}
}
if(keycode==38)
{
currow=currow-1;
if(currow<=0){currow=$('#casetable tr').length-1;lastrow=1;}
}
$('#row'+currow).addClass('rowhover');
$('#row'+lastrow).removeClass('rowhover');
document.getElementById('row'+currow).focus();
lastrow=currow;
}
}
function callkeydownhandler(evnt) {
var ev = evnt;
var focusedRow = ev.target && ev.target.tagName === "TR" ? ev.target : null;
if ((ev.key === "Enter" || ev.keyCode === 13) && focusedRow) {
ev.preventDefault();
GetRowData(focusedRow);
return;
}
keyListen('','',ev);
}
window.document.addEventListener("keydown", callkeydownhandler, false);

View File

@@ -1,754 +0,0 @@
var records=new Array(1);
var fields=new Array(1);
var recIndx = 0;
var recpos = 0;
var autocut = 0;
var SameAddr=new Array(0);
var AddrElem=new Array(4);
var selectedAddr=-1;
var FocusAfter="customername";
AddrElem[0]=["rv","raddr1","raddr2","raddr3","rlandmark","Rcolony","colr","rcity","rpincode","rphone"];
AddrElem[1]=["ov","companyname","oaddr1","oaddr2","oaddr3","olandmark","Ocolony","colo","ocity","opincode","ophone","extension"];
AddrElem[2]=["pv","paddr1","paddr2","paddr3","plandmark","Pcolony","colp","pcity","ppincode"];
AddrElem[3]=["bankcode","bankcode","bank_branch_id","product","loanamount","apptype","contactperson","specialinst"];
function InitPage(port,viscontents)
{
centerDivBoth("formcontainer","H");
HideSections('rtv');
HideSections('otv');
HideSections('section');
UnhideSections(viscontents,ColDelim);
$("#portfolio_id").val(port);
if(port>0)
{
if(document.getElementById("ajaxmsg") !== null)
{
CallMessage('1001AJX:warning:Another operation is being processed, please wait..',3000,200,300);
return;
}
LoadingMsg("Fetching records, please wait...","ajaxmsg");
RunAjax("GET","punchedrecs","val0="+port+"&val1="+($("#dynamicfields").val())+"&val2="+($("#uuid").val()),1);
}
}
function ValidateSubmitForm(FormName)
{
var Chkresi=document.getElementById('rv');
var Chkoff=document.getElementById('ov');
var Chkprop=document.getElementById('pv');
if(Chkresi.checked || Chkoff.checked || Chkprop.checked || document.getElementById('rtv').checked || document.getElementById('otv').checked || document.getElementById('refv').checked)
{
validate(document.getElementById('applno'),'t','AlphaNumeric');
validate(document.getElementById('bank_branch_id'),'t','');
validate(document.getElementById('product'),'t','');
validate(document.getElementById('customername'),'t','AlphaSpace');
validate(document.getElementById('apptype'),'t','');
if(Chkresi.checked)
{
CheckForm(Chkresi,'raddr1,raddr2,raddr3,rlandmark,colr,rcity,rpincode','t,f,t,f,t,t,f','SplInstruction,SplInstruction,SplInstruction,SplInstruction,SplInstruction,,Pincode');
if(document.getElementById('Rcolony').value=='' || document.getElementById('Rcolony').value=='0')
{
highlightField(document.getElementById('colr'));
}
}
if(Chkoff.checked)
{
CheckForm(Chkoff,'companyname,oaddr1,oaddr2,oaddr3,olandmark,colo,ocity,opincode,department,designation','f,t,f,t,f,t,t,f,f,f','SplInstruction,SplInstruction,SplInstruction,SplInstruction,SplInstruction,SplInstruction,,Pincode,SplInstruction,SplInstruction');
if(document.getElementById('Ocolony').value=='' || document.getElementById('Ocolony').value=='0')
{
highlightField(document.getElementById('colo'));
}
}
if(document.getElementById('rtv').checked)
{
CheckForm(document.getElementById('rtv'),'rphone','t','Phone');
}
if(document.getElementById('otv').checked)
{
CheckForm(document.getElementById('otv'),'ophone','t','Phone');
}
if(Chkprop.checked)
{
CheckForm(Chkprop,'paddr1,paddr2,paddr3,plandmark,colp,pcity,ppincode','t,f,t,f,t,t,f','SplInstruction,SplInstruction,SplInstruction,SplInstruction,SplInstruction,,Pincode');
if(document.getElementById('Pcolony').value=='' || document.getElementById('Pcolony').value=='0')
{
highlightField(document.getElementById('colp'));
}
}
if(document.getElementById('refv').checked)
{
CheckForm(document.getElementById('refv'),'refname1,refaddress1,refcontactno1','t,f,t','AlphaSpace,SplInstruction,Phone');
}
if (invalidFields>0)
{
CallMessage('VLFRM:error:There are one or more error(s) in form. Please correct them and try again.',3000,200,300);
}
else
{
if(document.getElementById("ajaxmsg") !== null)
{
CallMessage('1001AJX:warning:Another operation is being processed, please wait..',3000,200,300);
return;
}
var Qstr=PrepareQStr();
if(document.getElementById("ajaxmsg") !== null)
{
CallMessage('1001AJX:warning:Another operation is being processed, please wait..',3000,200,300);
return false;
}
LoadingMsg("Saving details, please wait...","ajaxmsg");
RunAjax("GET","updatecase",Qstr,2);
}
}
else
{
CallMessage('VLFRM:error:Atleast one address verification is mandatory.',3000,200,300);
}
}
function PrepareQStr()
{
var val0='';
var val1='';
var indx=3;
autocut=$("#autocut").is(":checked") ? 1 : 0;
var lindx=fields[0].length-1;
var cid=$("#case_id").val();
var temp='';
for(indx;indx<lindx;indx++)
{
temp='';
if($("#"+fields[0][indx]).length > 0)
{
if(fields[0][indx]=='rv' || fields[0][indx]=='sradd' || fields[0][indx]=='rtv' ||
fields[0][indx]=='ov' || fields[0][indx]=='soadd' || fields[0][indx]=='otv' || fields[0][indx]=='rco'
|| fields[0][indx]=='pv' || fields[0][indx]=='rcp' || fields[0][indx]=='ocp' || fields[0][indx]=='spadd'|| fields[0][indx]=='refv'|| fields[0][indx]=='docv')
{
temp=$("#"+fields[0][indx]).is(':checked') ? '1':'0';
}
else if(fields[0][indx]=='portfolio_id' || fields[0][indx]=='bank_branch_id' || fields[0][indx]=='company_id' || fields[0][indx]=='branch_id' || fields[0][indx]=='Rcolony' || fields[0][indx]=='Ocolony' || fields[0][indx]=='Pcolony')
{
temp=$("#"+fields[0][indx]).val()=='' ? '0':$("#"+fields[0][indx]).val();
}
else if(fields[0][indx]=='colr' || fields[0][indx]=='colo' || fields[0][indx]=='colp' || fields[0][indx]=='status')
{
temp=$("#"+fields[0][indx]).val();
records[recpos][indx]=temp.replace(/\'/g,'');
continue;
}
else
{
temp="''"+$("#"+fields[0][indx]).val().replace(/,/g, ' ')+"''";
}
val0=val0+fields[0][indx]+',';
val1=val1+temp+",";
records[recpos][indx]=temp.replace(/\'/g,'');
}
else
{
val0=val0+fields[0][indx]+',';
val1=val1+"NULL,";
records[recpos][indx]=temp.replace(/\'/g,'');
}
}
val1=val1.replace(/&/g,'~AmP~');
return "val0="+val0+"&val1="+val1+"&val2="+cid+"&val3="+($("#uuid").val())+"&val4="+autocut+"&val5="+($("#usid").val())+"&val6="+($("#portfolio_id").val())+"&val7="+($("#formmode").val());
}
function GotoRecord(el,searchtype)
{
recno=el.value;
if(recno!='')
{
if(searchtype == 'recno')
{
if(recno > recIndx || recno <=0)
{
CallMessage('1001IRNG:error:Invalid input. Out of range',3000,200,300);
}
else
{
recpos=recno-1;
FillDetails(recpos);
}
}
else
{
for(index = 0; index < records.length; index++ )
{
if( records[index][4] === recno ) {
recpos = index;
FillDetails(recpos);
break;
}
}
}
}
}
function AddNewRecord()
{
if(recIndx== 0 || records[recIndx-1][0]!='0')
{
var cols=fields[0].length;
recIndx = recIndx+1;
recpos = recIndx-1;
records[recpos]=new Array(cols);
records[recpos][0]='0';
records[recpos][1]=$("#portfolio_id").val();
records[recpos][cols-4]='0';
records[recpos][cols-3]=$("#company_id").val();
records[recpos][cols-2]=$("#branch_id").val();
records[recpos][cols-1]='';
records[recpos][2]='******';
}
else
{
recpos=recIndx-1;
}
FillDetails(recpos);
}
function AfterResponse(response,oprID)
{
var rindx=0;
if(oprID==1)
{
$("#ajaxmsg").remove();
if(response.trim().search('Error')==-1)
{
var rows=response.split(RowDelim);
for(rindx=0;rindx<rows.length-1;rindx++)
{
var cindx=0;
var cols=rows[rindx].split(ColDelim);
if(rindx==0)
{
fields[rindx]=new Array(cols.length);
}
else
{
records[rindx-1]=new Array(cols.length);
}
for(cindx=0;cindx<cols.length;cindx++)
{
if(rindx==0)
{
fields[rindx][cindx]=cols[cindx];
}
else
{
records[rindx-1][cindx]=cols[cindx];
}
}
}
}
else
{
CallMessage(response,3000,200,300);
}
recIndx= rindx==0 ? rindx : rindx-1;
$("#recfound").html("<b>( 0 / "+(recIndx==0 ? "0" : recIndx)+" )</b>");
recpos=recIndx==0 ? 0 : recIndx-1;
FillDetails(recpos);
}
else if(oprID==2)
{
collen=fields[0].length;
$("#ajaxmsg").remove();
if(response.trim().search('Error')==-1)
{
if(autocut==1)
{
records[recpos][collen-4]='1';
}
if($("#case_id").val()!='0')
{
findRecord(3);
}
else
{
records[recpos][2]=response.split(ColDelim)[0];
records[recpos][0]=response.split(ColDelim)[1];
records[recpos][collen-1]=response.split(ColDelim)[2];
AddNewRecord();
}
CallMessage('1001IRNG:info:Record updated successfully',3000,200,300);
}
else
{
records[recpos][collen-4]='-1';
CallMessage(response,3000,200,300);
}
}
else if(oprID==19 || oprID==20 || oprID==21 || oprID==22)
{
TabRows=response.split(RowDelim);
for(indx=0;indx<TabRows.length-1;indx++)
{
if($("#portfolio_id").val()==81)
{
var appl = $("#applno").val();
alert('Application number '+appl+' already exists.');
appl= (appl.search('_1') < 0 ? appl+'_1' : appl.split('_')[0]+'_'+(parseInt(appl.split('_')[1])+1));
$("#applno").val(appl);
validate(document.getElementById('applno'),'t','AlphaNumeric');
document.getElementById('applno').focus();
}
else
{
TabCols=TabRows[indx].split(ColDelim);
SameAddr[indx]=new Array(TabCols.length);
for(cindx=0;cindx<TabCols.length;cindx++)
{
SameAddr[indx][cindx]=TabCols[cindx];
}
}
}
SelectAddr(oprID-19);
}
}
function findRecord(arrOpr)
{
tempPos= recpos;
maxLen= recIndx-1;
if(arrOpr==1) tempPos=0;
if(arrOpr==2)
{
if(tempPos>0) tempPos=tempPos-1;
else return false;
}
if(arrOpr==3)
{
if(tempPos<maxLen) tempPos=tempPos+1;
else return false;
}
if(arrOpr==4) tempPos=maxLen;
recpos= tempPos;
FillDetails(recpos);
}
function FillDetails(indx)
{
if(recIndx > 0)
{
document.forms['casedetails'].reset();
$("#recfound").html("<b>( "+(indx+1)+" / "+(recIndx==0 ? "0" : recIndx)+" )</b>");
var findx=0;
for(findx=0;findx<fields[0].length;findx++)
{
if($("#"+fields[0][findx]).length > 0)
{
if(fields[0][findx]=='rv' || fields[0][findx]=='sradd' || fields[0][findx]=='rtv' ||
fields[0][findx]=='ov' || fields[0][findx]=='soadd' || fields[0][findx]=='otv' || fields[0][findx]=='rco'
|| fields[0][findx]=='pv' || fields[0][findx]=='rcp' || fields[0][findx]=='ocp' || fields[0][findx]=='spadd'|| fields[0][findx]=='refv'|| fields[0][findx]=='docv')
{
if(fields[0][findx]=='docv')
{
if($("#"+fields[0][findx]).is(":visible"))
{
$("#"+fields[0][findx]).attr('checked',true);
}
}
else
{
if(records[indx][findx]=='1')
{
$("#"+fields[0][findx]).attr('checked',true);
}
else
{
$("#"+fields[0][findx]).attr('checked',false);
}
}
}
else
{
$("#"+fields[0][findx]).val(records[indx][findx]);
}
}
}
if($("#status").val()=='1')
{
$("#btnsave").hide();
}
else
{
$("#btnsave").show();
}
FireClickEvents();
document.getElementById("applno").focus();
}
else
{
CallMessage('5005MQRY:error:No records found',3000,200,300);
AddNewRecord();
}
}
function FireClickEvents()
{
HandleClick(document.getElementById('rv'));
HandleClick(document.getElementById('ov'));
HandleClick(document.getElementById('rtv'));
HandleClick(document.getElementById('otv'));
HandleClick(document.getElementById('pv'));
HandleClick(document.getElementById('refv'));
}
function FireToggleEvents()
{
ToggleChks((document.getElementById('rv').checked && document.getElementById('ov').checked),'rco'+ColDelim,ColDelim);
ToggleChks((document.getElementById('apptype').value.toUpperCase()!='APPLICANT' && document.getElementById('apptype').value.toUpperCase()!='-1'),'sradd!C0L!soadd!C0L!spadd!C0L!','!C0L!');
ToggleChks((document.getElementById('rv').checked),'rcp'+ColDelim,ColDelim);
ToggleChks((document.getElementById('ov').checked),'ocp'+ColDelim,ColDelim);
}
function HandleClick(el)
{
if(el.id=='rv')
{
setFormValidation(el,'FormPanel2','raddr1,raddr2,raddr3,rlandmark,rcity,colr,rpincode','t,f,t,f,t,t,f','SplInstruction,SplInstruction,SplInstruction,SplInstruction,,SplInstruction,Pincode',document.getElementById('rtv').checked);
EnableDisableFields(el.checked,'raddr1,raddr2,raddr3,rlandmark,colr,rpincode',',');
}
if(el.id=='rtv')
{
setFormValidation(el,'FormPanel2','rphone','t','Phone',document.getElementById('rv').checked);
}
if(el.id=='ov')
{
setFormValidation(el,'FormPanel3','companyname,oaddr1,oaddr2,oaddr3,olandmark,ocity,colo,opincode,department,designation','f,t,f,t,f,t,t,f,f,f','SplInstruction,SplInstruction,SplInstruction,SplInstruction,SplInstruction,,SplInstruction,Pincode,SplInstruction,SplInstruction',document.getElementById('otv').checked);
EnableDisableFields(el.checked,'oaddr1,oaddr2,oaddr3,olandmark,colo,opincode',',');
}
if(el.id=='rco')
{
if(el.checked)
{
AutoFill('rco',1);
}
else
{AutoFill('rco',0);}
}
if(el.id=='otv')
{
setFormValidation(el,'FormPanel3','ophone','t','Phone',document.getElementById('ov').checked);
}
if(el.id=='pv')
{
setFormValidation(el,'FormPanel4','paddr1,paddr2,paddr3,plandmark,pcity,colp,ppincode','t,f,t,f,t,t,f','SplInstruction,SplInstruction,SplInstruction,SplInstruction,,SplInstruction,Pincode',false);
EnableDisableFields(el.checked,'paddr1,paddr2,paddr3,plandmark,colp,ppincode',',');
if(!el.checked)
{
chkrcp=document.getElementById('rcp');
chkrcp.checked=false;
chkocp=document.getElementById('ocp');
chkocp.checked=false;
}
}
if(el.id=='rcp')
{
if(el.checked)
{
AutoFill('rcp',1);
chkocp=document.getElementById('ocp');
chkocp.checked=false;
chkprop=document.getElementById('pv');
chkprop.checked=true;
HandleClick(chkprop);
}
else
{AutoFill('rcp',0);}
}
if(el.id=='ocp')
{
if(el.checked)
{
AutoFill('ocp',1);
chkrcp=document.getElementById('rcp');
chkrcp.checked=false;
chkprop=document.getElementById('pv');
chkprop.checked=true;
HandleClick(chkprop);
}
else
{AutoFill('ocp',0);}
}
if(el.id=='refv')
{
setFormValidation(el,'FormPanel5','refname1,refaddress1,refcontactno1','t,f,t','AlphaSpace,SplInstruction,Phone',false);
}
}
function setFormValidation(Elem,FormPanel,ChildElems,IsRequired,Validation,CounterPartElem)
{
/*if(Elem.checked && !CounterPartElem)
{
hideForm(Elem.id, FormPanel);
}
if(!Elem.checked)
{
CheckForm(Elem,ChildElems,IsRequired,Validation);
if(!CounterPartElem)
{
hideForm(Elem.id, FormPanel);
}
}*/
if(Elem.checked || CounterPartElem)
{
UnhideSections(FormPanel+ColDelim, ColDelim);
}
else
{
HideSections(FormPanel);
}
CheckForm(Elem,ChildElems,IsRequired,Validation);
FireToggleEvents();
}
function CheckForm(Elem,ChildElems,IsRequired,Validation)
{
var Childs=ChildElems.split(",");
var IsChildReq=IsRequired.split(",");
var ValidString=Validation.split(",");
for(Indx=0;Indx<Childs.length;Indx++)
{
validate(document.getElementById(Childs[Indx]),Elem.checked ? IsChildReq[Indx]:'f',ValidString[Indx]);
}
}
function AutoFill(Opt,FillMode)
{
var SourceFields="";
var TargetFields="";
var isSameAdd=false;
if(Opt=='rco')
{
SourceFields="raddr1"+ColDelim+"raddr2"+ColDelim+"raddr3"+ColDelim+"Rcolony"+ColDelim+"colr"+ColDelim+"rcity"+ColDelim+"rlandmark"+ColDelim+"rpincode"+ColDelim+"rphone";
TargetFields="oaddr1"+ColDelim+"oaddr2"+ColDelim+"oaddr3"+ColDelim+"Ocolony"+ColDelim+"colo"+ColDelim+"ocity"+ColDelim+"olandmark"+ColDelim+"opincode"+ColDelim+"ophone";
if(document.getElementById('Rcolony').value==document.getElementById('Ocolony').value)
{
isSameAdd=true;
}
}
else if(Opt=='rcp')
{
SourceFields="raddr1"+ColDelim+"raddr2"+ColDelim+"raddr3"+ColDelim+"Rcolony"+ColDelim+"colr"+ColDelim+"rcity"+ColDelim+"rlandmark"+ColDelim+"rpincode";
TargetFields="paddr1"+ColDelim+"paddr2"+ColDelim+"paddr3"+ColDelim+"Pcolony"+ColDelim+"colp"+ColDelim+"pcity"+ColDelim+"plandmark"+ColDelim+"ppincode";
if(document.getElementById('Rcolony').value==document.getElementById('Pcolony').value)
{
isSameAdd=true;
}
}
else if(Opt=='ocp')
{
SourceFields="oaddr1"+ColDelim+"oaddr2"+ColDelim+"oaddr3"+ColDelim+"Ocolony"+ColDelim+"colo"+ColDelim+"ocity"+ColDelim+"olandmark"+ColDelim+"opincode";
TargetFields="paddr1"+ColDelim+"paddr2"+ColDelim+"paddr3"+ColDelim+"Pcolony"+ColDelim+"colp"+ColDelim+"pcity"+ColDelim+"plandmark"+ColDelim+"ppincode";
if(document.getElementById('Ocolony').value==document.getElementById('Pcolony').value)
{
isSameAdd=true;
}
}
if(FillMode==1)
{
CopyDetails(SourceFields,TargetFields);
}
else if(FillMode==0 && isSameAdd)
{
ClearDetails(TargetFields);
}
}
function ToggleChks(IsVisible,ChildElems,Delim)
{
if(IsVisible)
{
UnhideSections(ChildElems,Delim);
}
else
{
var Childs=ChildElems.split(Delim);
for(indx=0;indx<Childs.length-1;indx++)
{
HideSections(Childs[indx]);
document.getElementById(Childs[indx]).checked=false;
}
}
}
function ClearDetails(TargetFields)
{
if(TargetFields.length!=0)
{
var TargetList=TargetFields.split(ColDelim);
if(TargetList.length==TargetList.length)
{
for(pos=0;pos<TargetList.length;pos++)
{
$("#"+TargetList[pos]).val("");
}
}
}
}
function CopyDetails(SourceFields,TargetFields)
{
if(SourceFields.length!=0 && TargetFields.length!=0)
{
var SourceList=SourceFields.split(ColDelim);
var TargetList=TargetFields.split(ColDelim);
if(SourceList.length==TargetList.length)
{
for(pos=0;pos<SourceList.length;pos++)
{
$("#"+TargetList[pos]).val($("#"+SourceList[pos]).val());
}
}
}
}
function AfterOptSelect(ElemToRemove,OprID)
{
FillSameDet(selectedAddr, OprID);
selectedAddr=-1;
ElemToRemove.parentNode.removeChild(ElemToRemove);
}
function ShowAddrOptions(OprID)
{
var optDiv=document.createElement("div");
var Addr="";
optDiv.setAttribute("id","optDiv");
optDiv.setAttribute("class","FormPanel");
optDiv.setAttribute("style","font-family:Tahoma;overflow:visible");
var OptionPanel="<div id='TablePanel' class='tableContainer'><table border='0' cellspacing='0' width='100%' id='cutlist'><thead class='thead'><tr title='Row Title'><td colspan='2'>Available Addresses</td></tr></thead><tbody class='scrollContent'>";
for(indx=0;indx<SameAddr.length;indx++)
{
OptionPanel=OptionPanel+"<tr><td><input type='radio' name='rb1' id='rb"+indx+"' value='"+indx+"' onclick='selectedAddr=this.value;' /></td>";
OptionPanel=OptionPanel+"<td style='padding-right:5px'>";
for(cindx=0;cindx<4;cindx++)
{
Addr=Addr+" "+SameAddr[indx][cindx];
}
OptionPanel=OptionPanel+""+Addr+"</td></tr>";
Addr="";
}
OptionPanel=OptionPanel+"<tr><td colspan='2'><input type='button' class='button' name='btnok' style='margin-top:5px;float:right' value='OK' id='btnok' accesskey='K' onclick=\"AfterOptSelect(document.getElementById('inptDialog'),"+OprID+");\"";
OptionPanel=OptionPanel+"</tbody></table></div>";
optDiv.innerHTML=OptionPanel;
ShowInputDialog(optDiv,"Select Address","hint","inptDialog");
document.getElementById('rb0').focus();
}
function FillSameDet(AddrIndex,OprID)
{
if(!(AddrIndex < 0))
{
for(cindx=0;cindx<SameAddr[AddrIndex].length;cindx++)
{
$("#"+AddrElem[OprID][cindx+1]).val((SameAddr[AddrIndex][cindx]));
}
document.getElementById(FocusAfter).focus();
ToggleChks((document.getElementById('apptype').value.toUpperCase()!='APPLICANT' && document.getElementById('apptype').value.toUpperCase()!='-1'),'sradd!C0L!soadd!C0L!spadd!C0L!','!C0L!');
}
else
{
document.getElementById(AddrElem[OprID][0]).focus();
if(document.getElementById(AddrElem[OprID][0]).type=='checkbox'){document.getElementById(AddrElem[OprID][0]).checked=false;}
}
}
function SelectAddr(OprID)
{
if(SameAddr.length>1)
{
ShowAddrOptions(OprID);
}
else
{
FillSameDet(0,OprID);
}
}
function FindSameDet(Elm,Visit,focAfter)
{
if($("#case_id").val()!='0' && Visit=='A')
{
return;
}
else
{
FocusAfter=focAfter;
var procFlag=true;
if(Elm.type=='checkbox')
{
procFlag=Elm.checked;
}
if(procFlag)
{
Applno=document.getElementById('applno').value;
if(Applno.length==0)
{
if(Elm.type=='checkbox'){Elm.checked=false;}
CallMessage('VLFRM:error:Please enter application number.',3000,200,300);
document.getElementById('applno').focus();
return false;
}
else
{
SameAddr=new Array(0); // Empty Address Array
oprId=(Visit=='R' ? 19:Visit=='O' ? 20:Visit=='P' ? 21:22);
QryStr="val="+Applno+"&val1="+$("#portfolio_id").val()+"&val2="+oprId;
RunAjax("GET","findsdet",QryStr,oprId);
}
}
}
}
function FindStr(el,elmids,rstfld)
{
el.value=el.value.split('->')[0];
var skey=el.value.trim().toUpperCase();
if(skey!='UNKNOWN' && skey!='-1')
{
var elms=elmids.split(ColDelim);
var indx=0;
for(indx=0;indx<elms.length;indx++)
{
if($("#"+elms[indx]).val().toUpperCase().search(skey)>-1)
{
return true;
}
}
}
else
{
return true;
}
return false;
}
function HandleBlur(el)
{
if(el.id=='rcity' || el.id=='ocity' || el.id=='pcity')
{
var pel= (el.id=='rcity' ? 'Rcolony':(el.id=='ocity' ? 'Ocolony':'Pcolony'));
var cel= (el.id=='rcity' ? 'raddr':(el.id=='ocity' ? 'oaddr':'paddr'));
var hel= (el.id=='rcity' ? 'colr':(el.id=='ocity' ? 'colo':'colp'));
var chk= (el.id=='rcity' ? 'rv':(el.id=='ocity' ? 'ov':'pv'));
if(!FindStr(el,cel+'2!C0L!'+cel+'3'))
{
CallMessage("1001AREA:error:Invalid area.", 3000, 200, 300);
$(el).val("-1");
$("#"+pel).val("");
$("#"+hel).val("");
}
validate(el,document.getElementById(chk).checked ? 't':'f','');
}
if(el.id=='colr' || el.id=='colo' || el.id=='colp')
{
var pel= (el.id=='colr' ? 'rv':(el.id=='colo' ? 'ov':'pv'));
var cel= (el.id=='colr' ? 'raddr':(el.id=='colo' ? 'oaddr':'paddr'));
if(!FindStr(el,cel+'2!C0L!'+cel+'3'))
{
CallMessage("1001AREA:error:Invalid colony.", 3000, 200, 300);
$(el).val("");
}
if(el.value=='')
{
document.getElementsByName(el.id+'_hidden')[0].value='';
}
if(document.getElementsByName(el.id+'_hidden')[0].value=='')
{
el.value='';
}
validate(el,document.getElementById(pel).checked ? 't':'f','SplInstruction');
}
}

View File

@@ -1,425 +0,0 @@
//RowDelim="~R0W~";
//ColDelim="~C0L~";
var SameAddr=new Array(0);
var AddrElem=new Array(4);
var selectedAddr=-1;
var FocusAfter="CustomerName";
AddrElem[0]=["chksresi","ResiAdd1","ResiAdd2","ResiAdd3","ResiLandmark","ResiAdd3_hidden","ResiAdd3_citylist","ResiAdd3_Pincode","ResiPhone"];
AddrElem[1]=["chksoff","CompanyName","OffAdd1","OffAdd2","OffAdd3","OffLandmark","OffAdd3_hidden","OffAdd3_citylist","OffAdd3_Pincode","OffPhone","Extension"];
AddrElem[2]=["chksprop","PropAdd1","PropAdd2","PropAdd3","PropLandmark","PropAdd3_hidden","PropAdd3_citylist","PropAdd3_Pincode"];
AddrElem[3]=["BankCode","BankCode","branchlist","prodlist","LoanAmount","typelist","ContactPerson","splist"];
function SubmitPunching(pageURL,TargetWindow)
{
document.caseDetails.action=pageURL;
document.caseDetails.target=TargetWindow;
document.caseDetails.submit();
}
function FindSameDet(Elm,Visit,focAfter)
{
if($("#FormMode").val()=='2' && Visit=='A')
{
return;
}
else
{
FocusAfter=focAfter;
var procFlag=true;
if(Elm.type=='checkbox')
{
procFlag=Elm.checked;
}
if(procFlag)
{
Applno=document.getElementById('ApplNo').value;
if(Applno.length==0)
{
if(Elm.type=='checkbox'){Elm.checked=false;}
CallMessage('VLFRM:error:Please enter application number.',3000,200,300);
document.getElementById('ApplNo').focus();
return false;
}
else
{
SameAddr=new Array(0); // Empty Address Array
oprId=(Visit=='R' ? 19:Visit=='O' ? 20:Visit=='P' ? 21:22);
QryStr="val="+Applno+"&val1="+$("#portlist").val()+"&val2="+oprId;
RunAjax("GET","findsdet",QryStr,oprId);
}
}
}
}
function copyTelNo(isCopy,SourceElemId,TargetElemId)
{
if(isCopy)
{
var copyStr="/";
if(($("#"+TargetElemId).val().length) > 0)
{
copyStr=$("#"+TargetElemId).val()+"/"+$("#"+SourceElemId).val();
}
else
{
copyStr=$("#"+SourceElemId).val();
}
$("#"+TargetElemId).val(copyStr);
}
}
function SelectAddr(OprID)
{
if(SameAddr.length>1)
{
ShowAddrOptions(OprID);
}
else
{
FillSameDet(0,OprID);
}
}
function FillSameDet(AddrIndex,OprID)
{
if(!(AddrIndex < 0))
{
for(cindx=0;cindx<SameAddr[AddrIndex].length;cindx++)
{
$("#"+AddrElem[OprID][cindx+1]).val((SameAddr[AddrIndex][cindx]));
}
document.getElementById(FocusAfter).focus();
ToggleChks((document.getElementById('typelist').value.toUpperCase()!='APPLICANT' && document.getElementById('typelist').value.toUpperCase()!='-1'),'chksresi!C0L!chksoff!C0L!chksprop!C0L!','!C0L!');
}
else
{
document.getElementById(AddrElem[OprID][0]).focus();
if(document.getElementById(AddrElem[OprID][0]).type=='checkbox'){document.getElementById(AddrElem[OprID][0]).checked=false;}
}
}
function ShowAddrOptions(OprID)
{
var optDiv=document.createElement("div");
var Addr="";
optDiv.setAttribute("id","optDiv");
optDiv.setAttribute("class","FormPanel");
optDiv.setAttribute("style","font-family:Tahoma;overflow:visible");
var OptionPanel="<div id='TablePanel' class='tableContainer'><table border='0' cellspacing='0' width='100%' id='cutlist'><thead class='thead'><tr title='Row Title'><td colspan='2'>Available Addresses</td></tr></thead><tbody class='scrollContent'>";
for(indx=0;indx<SameAddr.length;indx++)
{
OptionPanel=OptionPanel+"<tr><td><input type='radio' name='rb1' id='rb"+indx+"' value='"+indx+"' onclick='selectedAddr=this.value;' /></td>";
OptionPanel=OptionPanel+"<td style='padding-right:5px'>";
for(cindx=0;cindx<4;cindx++)
{
Addr=Addr+" "+SameAddr[indx][cindx];
}
OptionPanel=OptionPanel+""+Addr+"</td></tr>";
Addr="";
}
OptionPanel=OptionPanel+"<tr><td colspan='2'><input type='button' class='button' name='btnok' style='margin-top:5px;float:right' value='OK' id='btnok' accesskey='K' onclick=\"AfterOptSelect(document.getElementById('inptDialog'),"+OprID+");\"";
OptionPanel=OptionPanel+"</tbody></table></div>";
optDiv.innerHTML=OptionPanel;
ShowInputDialog(optDiv,"Select Address","hint","inptDialog");
document.getElementById('rb0').focus();
}
function AfterOptSelect(ElemToRemove,OprID)
{
FillSameDet(selectedAddr, OprID);
selectedAddr=-1;
ElemToRemove.parentNode.removeChild(ElemToRemove);
}
function GatherRequirement(portID)
{
ClearDropDown("branch"+ColDelim+"product",ColDelim);
HideSections("section");
if(portID!=0)
{
QryStr="val0="+portID;
RunAjax("GET","filldds",QryStr,1);
}
}
function AfterResponse(AjaxResponse,OprID)
{
if(OprID==1)
{
ArrangePage(AjaxResponse);
}
else if(OprID==19 || OprID==20 || OprID==21 || OprID==22)
{
TabRows=AjaxResponse.split(RowDelim);
for(indx=0;indx<TabRows.length-1;indx++)
{
TabCols=TabRows[indx].split(ColDelim);
SameAddr[indx]=new Array(TabCols.length);
for(cindx=0;cindx<TabCols.length;cindx++)
{
SameAddr[indx][cindx]=TabCols[cindx];
}
}
SelectAddr(OprID-19);
}
}
function ArrangePage(AjaxResponse)
{
if(AjaxResponse!='')
{
var TempArr=AjaxResponse.split("#BRAN#");
var branch=TempArr[0];
TempArr=TempArr[1].split("#PROD#");
var product=TempArr[0];
var process=TempArr[1];
FillDD("branch",branch,RowDelim,ColDelim);
FillDD("product",product,RowDelim,ColDelim);
UnhideSections(process,ColDelim);
}
}
function ToggleChks(IsVisible,ChildElems,Delim)
{
if(IsVisible)
{
UnhideSections(ChildElems,Delim);
}
else
{
var Childs=ChildElems.split(Delim);
for(indx=0;indx<Childs.length-1;indx++)
{
HideSections(Childs[indx]);
document.getElementById(Childs[indx]).checked=false;
}
}
}
function setFormValidation(Elem,FormPanel,ChildElems,IsRequired,Validation,CounterPartElem)
{
if(Elem.checked && !CounterPartElem)
{
hideForm(Elem.id, FormPanel);
}
if(!Elem.checked)
{
CheckForm(Elem,ChildElems,IsRequired,Validation);
if(!CounterPartElem)
{
hideForm(Elem.id, FormPanel);
}
}
ToggleChks((document.getElementById('chkresi').checked && document.getElementById('chkoffice').checked),'chkrco'+ColDelim,ColDelim);
ToggleChks((document.getElementById('chkresi').checked),'chkrcp'+ColDelim,ColDelim);
ToggleChks((document.getElementById('chkoffice').checked),'chkocp'+ColDelim,ColDelim);
}
function AutoFill(Opt,FillMode)
{
var SourceFields="";
var TargetFields="";
var isSameAdd=false;
if(Opt=='chkrco')
{
SourceFields="ResiAdd1"+ColDelim+"ResiAdd2"+ColDelim+"ResiAdd3"+ColDelim+"ResiAdd3_hidden"+ColDelim+"ResiAdd3_citylist"+ColDelim+"ResiLandmark"+ColDelim+"ResiAdd3_Pincode"+ColDelim+"ResiPhone";
TargetFields="OffAdd1"+ColDelim+"OffAdd2"+ColDelim+"OffAdd3"+ColDelim+"OffAdd3_hidden"+ColDelim+"OffAdd3_citylist"+ColDelim+"OffLandmark"+ColDelim+"OffAdd3_Pincode"+ColDelim+"OffPhone";
if(document.getElementById('ResiAdd3_hidden').value==document.getElementById('OffAdd3_hidden').value)
{
isSameAdd=true;
}
}
else if(Opt=='chkrcp')
{
SourceFields="ResiAdd1"+ColDelim+"ResiAdd2"+ColDelim+"ResiAdd3"+ColDelim+"ResiAdd3_hidden"+ColDelim+"ResiAdd3_citylist"+ColDelim+"ResiLandmark"+ColDelim+"ResiAdd3_Pincode";
TargetFields="PropAdd1"+ColDelim+"PropAdd2"+ColDelim+"PropAdd3"+ColDelim+"PropAdd3_hidden"+ColDelim+"PropAdd3_citylist"+ColDelim+"PropLandmark"+ColDelim+"PropAdd3_Pincode";
if(document.getElementById('ResiAdd3_hidden').value==document.getElementById('PropAdd3_hidden').value)
{
isSameAdd=true;
}
}
else if(Opt=='chkocp')
{
SourceFields="OffAdd1"+ColDelim+"OffAdd2"+ColDelim+"OffAdd3"+ColDelim+"OffAdd3_hidden"+ColDelim+"OffAdd3_citylist"+ColDelim+"OffLandmark"+ColDelim+"OffAdd3_Pincode";
TargetFields="PropAdd1"+ColDelim+"PropAdd2"+ColDelim+"PropAdd3"+ColDelim+"PropAdd3_hidden"+ColDelim+"PropAdd3_citylist"+ColDelim+"PropLandmark"+ColDelim+"PropAdd3_Pincode";
if(document.getElementById('OffAdd3_hidden').value==document.getElementById('PropAdd3_hidden').value)
{
isSameAdd=true;
}
}
if(FillMode==1)
{
CopyDetails(SourceFields,TargetFields);
}
else if(FillMode==0 && isSameAdd)
{
ClearDetails(TargetFields);
}
}
function ClearDetails(TargetFields)
{
if(TargetFields.length!=0)
{
var TargetList=TargetFields.split(ColDelim);
if(TargetList.length==TargetList.length)
{
for(pos=0;pos<TargetList.length;pos++)
{
$("#"+TargetList[pos]).val("");
}
}
}
}
function CopyDetails(SourceFields,TargetFields)
{
if(SourceFields.length!=0 && TargetFields.length!=0)
{
var SourceList=SourceFields.split(ColDelim);
var TargetList=TargetFields.split(ColDelim);
if(SourceList.length==TargetList.length)
{
for(pos=0;pos<SourceList.length;pos++)
{
$("#"+TargetList[pos]).val($("#"+SourceList[pos]).val());
}
}
}
}
function CheckForm(Elem,ChildElems,IsRequired,Validation)
{
var Childs=ChildElems.split(",");
var IsChildReq=IsRequired.split(",");
var ValidString=Validation.split(",");
for(Indx=0;Indx<Childs.length;Indx++)
{
validate(document.getElementById(Childs[Indx]),Elem.checked ? IsChildReq[Indx]:'f',ValidString[Indx]);
}
}
function onLocalityBlur(el,IsRequired)
{
if(el.value=='')
{
document.getElementById(el.id+'_hidden').value='';
}
if(document.getElementById(el.id+'_hidden').value=='')
{
el.value='';
}
validate(el,IsRequired,'SplInstruction');
}
function ValidateSubmitForm(FormName)
{
var Chkresi=document.getElementById('chkresi');
var Chkoff=document.getElementById('chkoffice');
var Chkprop=document.getElementById('chkprop');
if(Chkresi.checked || Chkoff.checked || Chkprop.checked || document.getElementById('chkteler').checked || document.getElementById('chkteleo').checked || document.getElementById('chkref').checked || document.getElementById('chkdoc').checked)
{
validate(document.getElementById('ApplNo'),'t','AlphaNumeric');
validate(document.getElementById('branchlist'),'t','');
validate(document.getElementById('prodlist'),'t','');
validate(document.getElementById('CustomerName'),'t','AlphaSpace');
validate(document.getElementById('typelist'),'t','');
if(Chkresi.checked)
{
CheckForm(Chkresi,'ResiAdd1,ResiAdd2,ResiAdd3,ResiLandmark,ResiAdd3_citylist,ResiAdd3_Pincode','t,f,t,f,t,t','SplInstruction,SplInstruction,SplInstruction,SplInstruction,,Pincode');
if(document.getElementById('ResiAdd3_hidden').value=='' || document.getElementById('ResiAdd3_hidden').value=='0')
{
highlightField(document.getElementById('ResiAdd3'));
}
}
if(Chkoff.checked)
{
CheckForm(Chkoff,'CompanyName,OffAdd1,OffAdd2,OffAdd3,OffLandmark,OffAdd3_citylist,OffAdd3_Pincode,Department,Designation','f,t,f,t,f,t,t,f,f,t','SplInstruction,SplInstruction,SplInstruction,SplInstruction,SplInstruction,,Pincode,SplInstruction,SplInstruction');
if(document.getElementById('OffAdd3_hidden').value=='' || document.getElementById('OffAdd3_hidden').value=='0')
{
highlightField(document.getElementById('OffAdd3'));
}
}
if(document.getElementById('chkteler').checked)
{
CheckForm(document.getElementById('chkteler'),'ResiPhone','t','Phone');
}
if(document.getElementById('chkteleo').checked)
{
CheckForm(document.getElementById('chkteleo'),'OffPhone','t','Phone');
}
if(Chkprop.checked)
{
CheckForm(Chkprop,'PropAdd1,PropAdd2,PropAdd3,PropLandmark,PropAdd3_citylist,PropAdd3_Pincode','t,f,t,f,t,t','SplInstruction,SplInstruction,SplInstruction,SplInstruction,,Pincode');
if(document.getElementById('PropAdd3_hidden').value=='' || document.getElementById('PropAdd3_hidden').value=='0')
{
highlightField(document.getElementById('PropAdd3'));
}
}
if(document.getElementById('chkref').checked)
{
CheckForm(document.getElementById('chkref'),'Ref1Name,Ref1Address,Ref1Contactno','t,f,t','AlphaSpace,SplInstruction,Phone');
}
if (invalidFields>0)
{
CallMessage('VLFRM:error:There are one or more error(s) in form. Please correct them and try again.',3000,200,300);
}
else
{
SubmitForm('casesave','_parent',FormName);
}
}
else
{
CallMessage('VLFRM:error:Atleast one address verification is mandatory.',3000,200,300);
}
}
function HandleClick(el)
{
if(el.id=='chkresi')
{
setFormValidation(el,'FormPanel2','ResiAdd1,ResiAdd2,ResiAdd3,ResiLandmark,ResiAdd3_citylist,ResiAdd3_Pincode','t,f,t,f,t,t,f','SplInstruction,SplInstruction,SplInstruction,SplInstruction,,Pincode',document.getElementById('chkteler').checked);
EnableDisableFields(el.checked,'ResiAdd1,ResiAdd2,ResiAdd3,ResiLandmark,ResiAdd3_Pincode',',');
}
if(el.id=='chkteler')
{
setFormValidation(el,'FormPanel2','ResiPhone','t','Phone',document.getElementById('chkresi').checked);
}
if(el.id=='chkoffice')
{
setFormValidation(el,'FormPanel3','CompanyName,OffAdd1,OffAdd2,OffAdd3,OffLandmark,OffAdd3_citylist,OffAdd3_Pincode,Department,Designation','f,t,f,t,f,t,t,f,f,t','SplInstruction,SplInstruction,SplInstruction,SplInstruction,SplInstruction,,Pincode,SplInstruction,SplInstruction',document.getElementById('chkteleo').checked);
EnableDisableFields(el.checked,'OffAdd1,OffAdd2,OffAdd3,OffLandmark,OffAdd3_Pincode',',');
}
if(el.id=='chkrco')
{
if(el.checked)
{
AutoFill('chkrco',1);
}
else
{AutoFill('chkrco',0);}
}
if(el.id=='chkteleo')
{
setFormValidation(el,'FormPanel3','OffPhone','t','Phone',document.getElementById('chkoffice').checked);
}
if(el.id=='chkprop')
{
setFormValidation(el,'FormPanel4','PropAdd1,PropAdd2,PropAdd3,PropLandmark,PropAdd3_citylist,PropAdd3_Pincode','t,f,t,f,t,t','SplInstruction,SplInstruction,SplInstruction,SplInstruction,,Pincode',false);
EnableDisableFields(el.checked,'PropAdd1,PropAdd2,PropAdd3,PropLandmark,PropAdd3_Pincode',',');
}
if(el.id=='chkrcp')
{
if(el.checked)
{
AutoFill('chkrcp',1);
chkocp=document.getElementById('chkocp');
chkocp.checked=false;
chkprop=document.getElementById('chkprop');
chkprop.checked=true;
HandleClick(chkprop);
}
else
{AutoFill('chkrcp',0);}
}
if(el.id=='chkocp')
{
if(el.checked)
{
AutoFill('chkocp',1);
chkrcp=document.getElementById('chkrcp');
chkrcp.checked=false;
chkprop=document.getElementById('chkprop');
chkprop.checked=true;
HandleClick(chkprop);
}
else
{AutoFill('chkocp',0);}
}
}

View File

@@ -1,403 +0,0 @@
var records=new Array(1);
var fields=new Array(1);
var recIndx = 0;
var recpos = 0;
var FocusAfter="customername";
ajax_list_externalFile = "listservprovider";
var validateHidden = false;
function InitPage(port)
{
centerDivBoth("formcontainer","H");
$("#portfolio_id").val(port);
ManageButtons(true);
$("#btnsave").hide();
if(port>0)
{
if(document.getElementById("ajaxmsg") !== null)
{
CallMessage('1001AJX:warning:Another operation is being processed, please wait..',3000,200,300);
return;
}
LoadingMsg("Fetching records, please wait...","ajaxmsg");
RunAjax("GET","puncheddocrecs","val0="+port+"&val1="+($("#dynamicfields").val()),1);
}
}
function PrepareQStr()
{
var val0='';
var val1='';
var indx=2;
autocut=0;
var lindx=fields[0].length-1;
var cid=$("#case_id").val();
var temp='';
for(indx;indx<lindx;indx++)
{
temp='';
if($("#"+fields[0][indx]).length > 0)
{
if(fields[0][indx]=='docv' || fields[0][indx]=='status')
{
continue;
}
else
{
temp="''"+$("#"+fields[0][indx]).val().replace(/,/g, ' ')+"''";
}
val0=val0+fields[0][indx]+',';
val1=val1+temp+",";
records[recpos][indx]=temp.replace(/\'/g,'');
}
else
{
val0=val0+fields[0][indx]+',';
val1=val1+"NULL,";
records[recpos][indx]=temp.replace(/\'/g,'');
}
}
val1=val1.replace(/&/g,'~AmP~');
return "val0="+val0+"&val1="+val1+"&val2="+cid+"&val3="+($("#uuid").val())+"&val4="+autocut+"&val5="+($("#usid").val())+"&val6="+($("#portfolio_id").val());
}
function GotoRecord(el)
{
recno=el.value;
if(recno!='')
{
if(recno > recIndx || recno <=0)
{
CallMessage('1001IRNG:error:Invalid input. Out of range',3000,200,300);
}
else
{
recpos=recno-1;
FillDetails(recpos);
}
}
}
function AddNewRecord()
{
if(recIndx== 0 || records[recIndx-1][0]!='0')
{
var cols=fields[0].length;
recIndx = recIndx+1;
recpos = recIndx-1;
records[recpos]=new Array(cols);
records[recpos][0]='0';
records[recpos][1]=$("#portfolio_id").val();
records[recpos][cols-4]='0';
records[recpos][cols-3]=$("#company_id").val();
records[recpos][cols-2]=$("#branch_id").val();
records[recpos][cols-1]='';
}
else
{
recpos=recIndx-1;
}
FillDetails(recpos);
}
function AfterResponse(response,oprID)
{
var rindx=0;
if(oprID==1)
{
$("#ajaxmsg").remove();
if(response.trim().search('Error')==-1)
{
var rows=response.split(RowDelim);
for(rindx=0;rindx<rows.length-1;rindx++)
{
var cindx=0;
var cols=rows[rindx].split(ColDelim);
if(rindx==0)
{
fields[rindx]=new Array(cols.length);
}
else
{
records[rindx-1]=new Array(cols.length);
}
for(cindx=0;cindx<cols.length;cindx++)
{
if(rindx==0)
{
fields[rindx][cindx]=cols[cindx];
}
else
{
records[rindx-1][cindx]=cols[cindx];
}
}
}
}
else
{
CallMessage(response,3000,200,300);
}
recIndx= rindx==0 ? rindx : rindx-1;
$("#recfound").html("<b>( 0 / "+(recIndx==0 ? "0" : recIndx)+" )</b>");
recpos=0;
FillDetails(recpos);
}
else if(oprID==2)
{
$("#ajaxmsg").remove();
collen=fields[0].length;
if(response.trim().search('Error')==-1)
{
if(autocut==1)
{
records[recpos][collen-4]='1';
}
if($("#case_id").val()!='0')
{
findRecord(3);
}
else
{
records[recpos][0]=response.split(ColDelim)[0];
records[recpos][collen-1]=response.split(ColDelim)[1];
AddNewRecord();
}
CallMessage('1001IRNG:info:Record updated successfully',3000,200,300);
}
else
{
records[recpos][collen-4]='-1';
CallMessage(response,3000,200,300);
}
}
else if(oprID==3)
{
$("#ajaxmsg").remove();
if(response.trim().search('Error')==-1)
{
CallMessage('1001IRNG:info:Record updated successfully',3000,200,300);
}
else
{
CallMessage(response,3000,200,300);
}
}
else if(oprID==4)
{
if(response.trim().search('Error')==-1)
{
FillDD("vendor_id",response,RowDelim,ColDelim);
if(currow != null)
{
$("#vendor_id").val($("#doclist tr:eq("+currow+")").find('td').eq(6).attr("id"));
}
}
else
{
CallMessage(response,3000,200,300);
}
}
else if(oprID==5)
{
if(response.trim().search('Error')==-1)
{
alert(response);
}
else
{
CallMessage(response,3000,200,300);
}
}
}
function findRecord(arrOpr)
{
tempPos= recpos;
maxLen= recIndx-1;
if(arrOpr==1) tempPos=0;
if(arrOpr==2)
{
if(tempPos>0) tempPos=tempPos-1;
else return false;
}
if(arrOpr==3)
{
if(tempPos<maxLen) tempPos=tempPos+1;
else return false;
}
if(arrOpr==4) tempPos=maxLen;
recpos= tempPos;
FillDetails(recpos);
}
function SearchRecord(elm)
{
var found=false;
var skey=elm.value.trim().toLowerCase();
for(rindx=0;rindx<records.length;rindx++)
{
if(records[rindx][3].trim().toLowerCase().search(skey)>-1)
{
recpos=rindx;
found=true;
FillDetails(recpos);
break;
}
}
if(!found)
{
CallMessage('NOREC1001:error:No record found.',3000,200,300);
}
}
function FillDetails(indx)
{
if(recIndx > 0)
{
CancelEdit();
document.forms['casedetails'].reset();
$("#doclist").html('');
resetDocForm();
$("#recfound").html("<b>( "+(indx+1)+" / "+(recIndx==0 ? "0" : recIndx)+" )</b>");
var cols = fields[0].length;
var findx=0;
for(findx=0;findx < cols;findx++)
{
if($("#"+fields[0][findx]).length > 0)
{
$("#"+fields[0][findx]).val(records[indx][findx]);
}
}
var data = jQuery.parseJSON(records[indx][cols-5].replace('},]}','}]}'));
var tdocs = data.docs.length;
for(indx = 0;indx < tdocs; indx++)
{
var did = data.docs[indx].doc_id;
data.docs[indx].doc_id="0";
AddDocRow(data.docs[indx],did,data.docs[indx].docvendor);
}
document.getElementById("applno").focus();
}
else
{
CallMessage('5005MQRY:error:No records found',3000,200,300);
AddNewRecord();
}
}
function EditBasicDetails()
{
EnableDisableFields(false);
ManageButtons(false);
}
function SaveBasicDetails()
{
if(confirm("Are you sure to update the details?"))
{
var QStr=PrepareQStr();
QStr=QStr+"&val7=2";
if(document.getElementById("ajaxmsg") !== null)
{
CallMessage('1001AJX:warning:Another operation is being processed, please wait..',3000,200,300);
return;
}
LoadingMsg("Updating details, please wait...","ajaxmsg");
RunAjax("POST","updatebdetails",QStr,3);
EnableDisableFields(true);
ManageButtons(true);
}
}
function CancelEdit()
{
SetPrevValues();
EnableDisableFields(true);
ManageButtons(true);
}
function EnableDisableFields(isEnabled)
{
var indx=2;
if(typeof fields[0]!=='undefined')
{
var lindx=fields[0].length-1;
for(indx;indx<lindx;indx++)
{
$("#"+fields[0][indx]).prop("disabled",isEnabled);
}
}
indx=0;
/*$("#applno").prop("disabled",isEnabled);
$("#customername").prop("disabled",isEnabled);
$("#dob").prop("disabled",isEnabled);
$("#loanamount").prop("disabled",isEnabled);
$("#bank_branch_id").prop("disabled",isEnabled);
$("#product").prop("disabled",isEnabled);
$("#apptype").prop("disabled",isEnabled);
$("#category").prop("disabled",isEnabled);*/
}
function SetPrevValues()
{
$("#applno").val(records[recpos][3]);
$("#customername").val(records[recpos][6]);
$("#dob").val(records[recpos][9]);
$("#loanamount").val(records[recpos][5]);
$("#bank_branch_id").val(records[recpos][2]);
$("#product").val(records[recpos][4]);
$("#apptype").val(records[recpos][7]);
$("#category").val(records[recpos][8]);
}
function ManageButtons(bmode)
{
if(bmode)
{
if($("#applno").val().length > 0)
{
$("#btnbedit").show();
$("#btnsave").hide();
$("#section7").show();
}
else
{
$("#btnbedit").hide();
$("#btnsave").show();
$("#section7").hide();
EnableDisableFields(false);
}
$("#btnbsave").hide();
$("#btnbcancel").hide();
}
else
{
$("#btnbedit").hide();
$("#btnbsave").show();
$("#btnbcancel").show();
}
}
function changeLabel(el)
{
$("#uniqueidentifier").html($('option:selected',el).attr("uniqueidentifier"));
$("#sprovider").html($('option:selected',el).attr("sprovider"));
$("#serviceprovider").val($('option:selected',el).attr("defsprovider"));
$("#serviceprovider_hidden").val("0");
if($('option:selected',el).attr("genlist")>0)
{
$("#serviceprovider_citylist").val($('option:selected',el).attr("genlist"));
$("#serviceprovider").attr('onkeyup',"ajax_showOptions(this,event)");
validateHidden = true;
}
else
{
$("#serviceprovider_citylist").val("0");
$("#serviceprovider").removeAttr('onkeyup');
validateHidden = false;
}
$("#uniqueno").attr("onblur","validate(this,'t','"+$('option:selected',el).attr("validuno")+"')");
$("#yearmon").html($('option:selected',el).attr("ymon"));
$("#yearmonth").attr("onblur","validate(this,'f','"+$('option:selected',el).attr("validymon")+"')");
ValidateEntry('f');
GetVerifierList(el);
}
function GetVerifierList(el)
{
$("#vendor_id").empty().append('<option value="-1" selected>SELECT</option>');
if(el.value != '-1')
{
RunAjax("POST","getdocverlist","val0="+el.value,4);
}
}

View File

@@ -0,0 +1,137 @@
(function (window, document) {
"use strict";
const API = Object.freeze({ key: "payload-key", save: "application-save" });
const BOOLEAN_FIELDS = Object.freeze({
residenceVerification: "rv",
residenceTelephoneVerification: "rtv",
officeVerification: "ov",
officeTelephoneVerification: "otv",
propertyVerification: "pv",
referenceVerification: "refv",
documentVerification: "docv",
residenceCoApplicant: "rco",
residenceCoProprietor: "rcp",
officeCoProprietor: "ocp",
sameResidenceAddress: "sradd",
sameOfficeAddress: "soadd",
samePropertyAddress: "spadd",
autoCutOff: "autocut"
});
const VALUE_FIELDS = Object.freeze({
applicationId: "case_id", portfolioId: "portfolio_id", bankBranchId: "bank_branch_id",
applicationNumber: "applno", bankCode: "bankcode", product: "product",
loanAmount: "loanamount", customerName: "customername", fatherName: "fathername",
applicationType: "apptype", category: "category", dateOfBirth: "dob",
contactPerson: "contactperson", mobileNumber: "mobileno", specialInstruction: "specialinst",
residenceAddress1: "raddr1", residenceAddress2: "raddr2", residenceAddress3: "raddr3",
residenceLandmark: "rlandmark", residenceColonyId: "Rcolony", residenceCity: "rcity",
residencePincode: "rpincode", residencePhone: "rphone", companyName: "companyname",
officeAddress1: "oaddr1", officeAddress2: "oaddr2", officeAddress3: "oaddr3",
officeLandmark: "olandmark", officeColonyId: "Ocolony", officeCity: "ocity",
officePincode: "opincode", department: "department", designation: "designation",
officePhone: "ophone", extension: "extension", propertyAddress1: "paddr1",
propertyAddress2: "paddr2", propertyAddress3: "paddr3", propertyLandmark: "plandmark",
propertyColonyId: "Pcolony", propertyCity: "pcity", propertyPincode: "ppincode",
referenceName1: "refname1", referenceAddress1: "refaddress1",
referenceContactNumber1: "refcontactno1", referenceName2: "refname2",
referenceAddress2: "refaddress2", referenceContactNumber2: "refcontactno2",
formMode: "formmode"
});
const INTEGER_FIELDS = new Set(["applicationId", "portfolioId", "bankBranchId", "residenceColonyId",
"officeColonyId", "propertyColonyId", "formMode"]);
const element = (id) => document.getElementById(id);
const value = (id) => {
const field = element(id);
if (!field) return "";
window.CygnusFormValidation.sanitizeElement(field);
return field.value?.trim() ?? "";
};
const integer = (id) => {
const parsed = Number.parseInt(value(id), 10);
return Number.isFinite(parsed) ? parsed : 0;
};
const checked = (id) => Boolean(element(id)?.checked);
function collectDynamicFields() {
const names = value("dynamicfields").split(window.ColDelim || "!C0L!").filter(Boolean);
return names.reduce((result, name) => {
if (/^(?:field(?:[1-9]|1[0-2]|150(?:_2)?)|dtfield1)$/i.test(name) && element(name)) {
result[name] = value(name);
}
return result;
}, {});
}
function collectCase() {
const details = {};
Object.entries(VALUE_FIELDS).forEach(([property, id]) => {
details[property] = INTEGER_FIELDS.has(property) ? integer(id) : value(id);
});
Object.entries(BOOLEAN_FIELDS).forEach(([property, id]) => { details[property] = checked(id); });
details.dynamicFields = collectDynamicFields();
return details;
}
function validateForm() {
const verificationIds = ["rv", "rtv", "ov", "otv", "pv", "refv", "docv"];
if (!verificationIds.some(checked)) {
notify("danger", "APP-4221", "At least one verification type is required.");
return false;
}
const validation = window.CygnusInitiationValidation.validateForm();
[["rv", "Rcolony", "colr"], ["ov", "Ocolony", "colo"], ["pv", "Pcolony", "colp"]]
.forEach(([flag, hidden, visible]) => {
if (checked(flag) && integer(hidden) === 0) window.highlightField(element(visible));
});
if (!validation.valid || document.querySelector(".matrix-validation-error-icon")) {
notify("danger", "APP-4221", "Correct the highlighted fields and submit the application again.");
validation.invalid[0]?.focus();
return false;
}
return true;
}
function notify(type, code, message, referenceId) {
window.CygnusNotifications.show({ type, code, message, referenceId });
}
function applyResult(result, originalApplicationId) {
element("case_id").value = result.applicationId;
if (element("mvcode")) element("mvcode").value = result.mvCode || "";
const currentRecord = window.records?.[window.recpos];
if (currentRecord && !Array.isArray(currentRecord)) {
currentRecord.case_id = result.applicationId;
currentRecord.mvcode = result.mvCode;
}
notify("success", "APP-2001", `Application ${result.mvCode || result.applicationId} saved successfully.`);
if (originalApplicationId === 0 && typeof window.AddNewRecord === "function") window.AddNewRecord();
else if (originalApplicationId > 0 && typeof window.findRecord === "function") window.findRecord(3);
}
async function save(event) {
event?.preventDefault();
if (!validateForm()) return false;
const button = element("btnsave");
if (button?.disabled) return false;
const details = collectCase();
if (button) button.disabled = true;
try {
const envelope = await window.CygnusPayloadCrypto.encrypt(details, { keyUrl: API.key });
const response = await fetch(API.save, { method: "POST", credentials: "same-origin",
headers: { "Content-Type": "application/json", Accept: "application/json" },
body: JSON.stringify(envelope) });
const body = await response.json().catch(() => null);
if (!response.ok || !body?.success) throw body?.message || body || {};
applyResult(body.data, details.applicationId);
} catch (error) {
notify("danger", error.code || "APP-5001",
error.message || "Cygnus could not save the application details.", error.referenceId);
} finally {
if (button) button.disabled = false;
}
return false;
}
window.CygnusInitiation = Object.freeze({ save });
}(window, document));

View File

@@ -0,0 +1,112 @@
(function () {
"use strict";
var currentRow = 0;
var lastRow = 0;
function rows() {
return Array.prototype.slice.call(document.querySelectorAll("#casetable tbody tr"));
}
function rowNumber(row) {
return Number((row.id || "").replace("row", "")) || 0;
}
function setActiveRow(row) {
if (!row) {
return;
}
rows().forEach(function (item) {
item.classList.remove("rowhover");
});
row.classList.add("rowhover");
currentRow = rowNumber(row);
lastRow = currentRow;
row.focus();
}
function hiddenValue(row, suffix) {
var input = document.getElementById(row.id + suffix);
return input ? input.value : "";
}
function submitForm(action, target, formId) {
if (typeof SubmitForm === "function") {
SubmitForm(action, target, formId);
return;
}
var form = document.getElementById(formId);
if (!form) {
return;
}
form.action = action;
form.target = target;
form.submit();
}
function openRow(row) {
if (!row) {
return;
}
var uuid = hiddenValue(row, "uuid");
var portfolioId = hiddenValue(row, "portid");
if (!uuid || !portfolioId) {
return;
}
document.getElementById("uuid").value = uuid;
document.getElementById("portlist").value = portfolioId;
submitForm("caseedit", "_parent", "caseGrid");
}
function moveSelection(direction) {
var allRows = rows();
if (allRows.length === 0) {
return;
}
var nextIndex = currentRow > 0 ? currentRow - 1 + direction : 0;
if (nextIndex < 0) {
nextIndex = allRows.length - 1;
}
if (nextIndex >= allRows.length) {
nextIndex = 0;
}
setActiveRow(allRows[nextIndex]);
}
function handleKeydown(event) {
var row = event.target && event.target.closest ? event.target.closest("#casetable tbody tr") : null;
if (event.key === "Enter" && row) {
event.preventDefault();
openRow(row);
return;
}
if (event.key === "ArrowDown") {
event.preventDefault();
moveSelection(1);
return;
}
if (event.key === "ArrowUp") {
event.preventDefault();
moveSelection(-1);
}
}
function init() {
rows().forEach(function (row) {
row.addEventListener("mouseenter", function () {
setActiveRow(row);
});
row.addEventListener("click", function () {
openRow(row);
});
});
document.addEventListener("keydown", handleKeydown, false);
}
window.CygnusEditCases = {
init: init,
openRow: openRow
};
window.InitPage = init;
}());

View File

@@ -0,0 +1,94 @@
(function (window, document) {
"use strict";
const element = (id) => document.getElementById(id);
const checked = (id) => Boolean(element(id)?.checked);
const requiredWhen = (id) => () => checked(id);
const sectionRule = (id, rule = {}) => Object.assign({ when: requiredWhen(id) }, rule);
const RULES = {
applno: { required: true, format: "AlphaNumeric", requiredMessage: "Application number is required." },
bank_branch_id: { required: true, requiredMessage: "Bank branch is required." },
product: { required: true, requiredMessage: "Product is required." },
customername: { required: true, format: "AlphaSpace", requiredMessage: "Customer name is required." },
apptype: { required: true, requiredMessage: "Application type is required." },
bankcode: { format: "AlphaNumeric" }, fathername: { format: "AlphaSpace" }, dob: { format: "Date" },
mobileno: { format: "AllowWrong" }, loanamount: { format: "LoanAmount" },
contactperson: { format: "AlphaSpace" }, specialinst: { format: "SplInstruction" },
raddr1: sectionRule("rv", { required: true, format: "SplInstruction" }), raddr2: sectionRule("rv", { format: "SplInstruction" }),
raddr3: sectionRule("rv", { required: true, format: "SplInstruction" }), rlandmark: sectionRule("rv", { format: "SplInstruction" }),
rcity: sectionRule("rv", { required: true }), colr: sectionRule("rv", { required: true, format: "SplInstruction" }),
rpincode: sectionRule("rv", { format: "Pincode" }), rphone: sectionRule("rtv", { required: true, format: "Phone" }),
companyname: sectionRule("ov", { format: "SplInstruction" }), oaddr1: sectionRule("ov", { required: true, format: "SplInstruction" }),
oaddr2: sectionRule("ov", { format: "SplInstruction" }), oaddr3: sectionRule("ov", { required: true, format: "SplInstruction" }),
olandmark: sectionRule("ov", { format: "SplInstruction" }), ocity: sectionRule("ov", { required: true }),
colo: sectionRule("ov", { required: true, format: "SplInstruction" }), opincode: sectionRule("ov", { format: "Pincode" }),
department: sectionRule("ov", { format: "SplInstruction" }), designation: sectionRule("ov", { format: "SplInstruction" }),
ophone: sectionRule("otv", { required: true, format: "Phone" }), extension: sectionRule("otv", { format: "Extension" }),
paddr1: sectionRule("pv", { required: true, format: "SplInstruction" }), paddr2: sectionRule("pv", { format: "SplInstruction" }),
paddr3: sectionRule("pv", { required: true, format: "SplInstruction" }), plandmark: sectionRule("pv", { format: "SplInstruction" }),
pcity: sectionRule("pv", { required: true }), colp: sectionRule("pv", { required: true, format: "SplInstruction" }),
ppincode: sectionRule("pv", { format: "Pincode" }), refname1: sectionRule("refv", { required: true, format: "AlphaSpace" }),
refaddress1: sectionRule("refv", { format: "SplInstruction" }),
refcontactno1: sectionRule("refv", { required: true, format: "Phone" }),
refname2: sectionRule("refv", { format: "AlphaSpace" }), refaddress2: sectionRule("refv", { format: "SplInstruction" }),
refcontactno2: sectionRule("refv", { format: "Phone" })
};
const VERIFICATION_GROUPS = Object.freeze({
rv: ["raddr1", "raddr2", "raddr3", "rlandmark", "rcity", "colr", "rpincode"],
rtv: ["rphone"],
ov: ["companyname", "oaddr1", "oaddr2", "oaddr3", "olandmark", "ocity", "colo",
"opincode", "department", "designation"],
otv: ["ophone"],
pv: ["paddr1", "paddr2", "paddr3", "plandmark", "pcity", "colp", "ppincode"],
refv: ["refname1", "refaddress1", "refcontactno1"]
});
function registerDynamicRules(form) {
if (!form) return;
form.querySelectorAll("#FormPanel6 [data-validation-required]").forEach(function (field) {
const label = field.closest(".widget")?.querySelector(".lblcontainer")?.textContent.trim();
RULES[field.id] = {
required: field.dataset.validationRequired === "true",
format: field.dataset.validationFormat || "",
requiredMessage: (label || "This dynamic field") + " is required."
};
});
}
function validateField(field) {
const target = typeof field === "string" ? element(field) : field;
const rule = target && RULES[target.id];
return !target || !rule || window.CygnusFormValidation.validateElement(target, rule);
}
function validateForm() {
return window.CygnusFormValidation.validateRules(RULES);
}
function validateVerification(verificationId) {
const invalid = [];
(VERIFICATION_GROUPS[verificationId] || []).forEach(function (fieldId) {
const field = element(fieldId);
if (!validateField(field)) invalid.push(field);
});
return { valid: invalid.length === 0, invalid: invalid };
}
function bind(form) {
if (!form || form.dataset.initiationValidationBound === "true") return;
registerDynamicRules(form);
form.dataset.initiationValidationBound = "true";
form.addEventListener("focusout", function (event) {
window.CygnusFormValidation.sanitizeElement(event.target);
validateField(event.target);
});
}
window.CygnusInitiationValidation = Object.freeze({
rules: RULES,
bind: bind,
validateField: validateField,
validateVerification: validateVerification,
validateForm: validateForm
});
}(window, document));

View File

@@ -0,0 +1,502 @@
/*
* Case Initiation page behaviour.
*
* This file owns record loading/navigation, verification-section state,
* address copying and duplicate-address lookup. The encrypted JSON save
* workflow is intentionally isolated in application-save.js.
*/
var records=[];
var recIndx = 0;
var recpos = 0;
var SameAddr=[];
var AddrElem=[
["rv","raddr1","raddr2","raddr3","rlandmark","Rcolony","colr","rcity","rpincode","rphone"],
["ov","companyname","oaddr1","oaddr2","oaddr3","olandmark","Ocolony","colo","ocity","opincode","ophone","extension"],
["pv","paddr1","paddr2","paddr3","plandmark","Pcolony","colp","pcity","ppincode"],
["bankcode","bankcode","bank_branch_id","product","loanamount","apptype","contactperson","specialinst"]
];
var selectedAddr=-1;
var FocusAfter="customername";
var CHECKBOX_FIELDS=new Set(["rv","sradd","rtv","ov","soadd","otv","rco","pv","rcp","ocp","spadd","refv","docv"]);
var DUPLICATE_OPERATION={R:19,O:20,P:21,A:22};
var PUNCHED_RECORDS_URL="punchedrecs";
var DUPLICATE_DETAILS_URL="findsdet";
var DUPLICATE_FIELDS={
19:["raddr1","raddr2","raddr3","rlandmark","rcolony","colr","rcity","rpincode","rphone"],
20:["companyname","oaddr1","oaddr2","oaddr3","olandmark","ocolony","colo","ocity","opincode","ophone","extension"],
21:["paddr1","paddr2","paddr3","plandmark","pcolony","colp","pcity","ppincode"],
22:["bankcode","bank_branch_id","product","loanamount","apptype","contactperson","specialinst"]
};
function InitPage()
{
var portField = document.getElementById("portfolio_id");
var initialPortField = document.getElementById("initial-portfolio-id");
var visibleContentsField = document.getElementById("visiblecontents");
var port = initialPortField ? initialPortField.value : (portField ? portField.value : "-1");
var viscontents = visibleContentsField ? visibleContentsField.value : "";
if (viscontents && viscontents.slice(-ColDelim.length) !== ColDelim) {
viscontents += ColDelim;
}
centerDivBoth("formcontainer","H");
HideSections('rtv');
HideSections('otv');
HideSections('section');
UnhideSections(viscontents,ColDelim);
if (portField) {
$(portField).val(port);
}
if(port>0)
{
if(document.getElementById("ajaxmsg") !== null)
{
CygnusNotifications.show({type:"warning",code:"1001AJX",message:"Another operation is being processed, please wait.",duration:3000});
return;
}
LoadingMsg("Fetching records, please wait...","ajaxmsg");
loadPunchedRecords(port,$("#uuid").val());
}
}
function GotoRecord(el,searchtype)
{
var recno=el.value;
if(recno!='')
{
if(searchtype == 'recno')
{
if(recno > recIndx || recno <=0)
{
CygnusNotifications.show({type:"danger",code:"1001IRNG",message:"Invalid input. Out of range",duration:3000});
}
else
{
recpos=recno-1;
FillDetails(recpos);
}
}
else
{
for(var index = 0; index < records.length; index++ )
{
if( records[index].applno === recno ) {
recpos = index;
FillDetails(recpos);
break;
}
}
}
}
}
function AddNewRecord()
{
if(recIndx==0 || String(records[recIndx-1].case_id)!='0')
{
recIndx = recIndx+1;
recpos = recIndx-1;
records[recpos]={case_id:'0',portfolio_id:$("#portfolio_id").val(),status:'0',
company_id:$("#company_id").val(),branch_id:$("#branch_id").val(),uuid:'',mvcode:'******'};
}
else
{
recpos=recIndx-1;
}
FillDetails(recpos);
}
async function loadPunchedRecords(portfolioId,documentCaseId)
{
try
{
var query=new URLSearchParams({portfolioId:portfolioId,documentCaseId:documentCaseId || ""});
var response=await fetch(PUNCHED_RECORDS_URL+"?"+query.toString(),{
method:"GET",credentials:"same-origin",headers:{Accept:"application/json"}
});
var body=await response.json().catch(function(){return null;});
if(!response.ok || !body || !body.success) throw body && body.message ? body.message : {};
records=Array.isArray(body.data && body.data.records) ? body.data.records : [];
recIndx=records.length;
updateRecordCounter(0,recIndx);
recpos=recIndx==0 ? 0 : recIndx-1;
FillDetails(recpos);
}
catch(error)
{
CygnusNotifications.show({type:"danger",code:error.code || "APP-5002",
message:error.message || "Cygnus could not load punched records.",referenceId:error.referenceId});
records=[];recIndx=0;recpos=0;FillDetails(0);
}
finally{$("#ajaxmsg").remove();}
}
function handleDuplicateDetailsResponse(records,oprID)
{
if($("#portfolio_id").val()==81)
{
for(var index=0;index<records.length;index++) incrementDuplicateApplicationNumber();
}
else SameAddr=records.map(function(record){
return DUPLICATE_FIELDS[oprID].map(function(field){return record[field] == null ? "" : record[field];});
});
SelectAddr(oprID-19);
}
async function loadDuplicateDetails(applicationNumber,portfolioId,queryId)
{
try
{
var query=new URLSearchParams({applicationNumber:applicationNumber,portfolioId:portfolioId,queryId:queryId});
var response=await fetch(DUPLICATE_DETAILS_URL+"?"+query.toString(),{
method:"GET",credentials:"same-origin",headers:{Accept:"application/json"}
});
var body=await response.json().catch(function(){return null;});
if(!response.ok || !body || !body.success) throw body && body.message ? body.message : {};
handleDuplicateDetailsResponse(Array.isArray(body.data && body.data.records) ? body.data.records : [],queryId);
}
catch(error)
{
CygnusNotifications.show({type:"danger",code:error.code || "APP-5002",
message:error.message || "Cygnus could not search existing application details.",referenceId:error.referenceId});
SameAddr=[];
SelectAddr(queryId-19);
}
}
function incrementDuplicateApplicationNumber()
{
var appl=$("#applno").val();
CygnusNotifications.show({type:"warning",code:"APP-DUPLICATE",message:"Application number "+appl+" already exists.",duration:3000});
appl=appl.search('_1')<0 ? appl+'_1' : appl.split('_')[0]+'_'+(parseInt(appl.split('_')[1])+1);
$("#applno").val(appl);
CygnusInitiationValidation.validateField(document.getElementById('applno'));
document.getElementById('applno').focus();
}
function findRecord(arrOpr)
{
var tempPos= recpos;
var maxLen= recIndx-1;
if(arrOpr==1) tempPos=0;
if(arrOpr==2)
{
if(tempPos>0) tempPos=tempPos-1;
else return false;
}
if(arrOpr==3)
{
if(tempPos<maxLen) tempPos=tempPos+1;
else return false;
}
if(arrOpr==4) tempPos=maxLen;
recpos= tempPos;
FillDetails(recpos);
}
function FillDetails(indx)
{
if(recIndx > 0)
{
document.forms['casedetails'].reset();
updateRecordCounter(indx+1,recIndx);
Object.keys(records[indx]).forEach(function(fieldName){fillRecordField(fieldName,records[indx][fieldName]);});
$("#btnsave").toggle($("#status").val()!='1');
FireClickEvents();
document.getElementById("applno").focus();
}
else
{
CygnusNotifications.show({type:"danger",code:"5005MQRY",message:"No records found",duration:3000});
AddNewRecord();
}
}
function fillRecordField(fieldName,fieldValue)
{
var field=document.getElementById(fieldName) || dynamicFieldElement(fieldName);
if(!field) return;
if(CHECKBOX_FIELDS.has(fieldName))
{
field.checked=fieldName=='docv' ? $(field).is(":visible") : fieldValue=='1';
return;
}
field.value=fieldValue;
}
function dynamicFieldElement(fieldName)
{
var dynamicFields=document.querySelectorAll("#FormPanel6 [id]");
for(var index=0;index<dynamicFields.length;index++)
if(dynamicFields[index].id.toLowerCase()==fieldName.toLowerCase()) return dynamicFields[index];
return null;
}
function updateRecordCounter(current,total)
{
$("#recfound").html("<b>( "+current+" / "+total+" )</b>");
}
function FireClickEvents()
{
["rv","ov","rtv","otv","pv","refv"].forEach(function(id){HandleClick(document.getElementById(id));});
}
function FireToggleEvents()
{
ToggleChks(document.getElementById('rv').checked && document.getElementById('ov').checked,["rco"]);
var applicationType=document.getElementById('apptype').value.toUpperCase();
ToggleChks(applicationType!='APPLICANT' && applicationType!='-1',["sradd","soadd","spadd"]);
ToggleChks(document.getElementById('rv').checked,["rcp"]);
ToggleChks(document.getElementById('ov').checked,["ocp"]);
}
function HandleClick(el)
{
var handler=VERIFICATION_HANDLERS[el.id];
if(handler) handler(el);
}
var VERIFICATION_HANDLERS={
rv:function(el){
setFormValidation(el,'FormPanel2',document.getElementById('rtv').checked);
EnableDisableFields(el.checked,'raddr1,raddr2,raddr3,rlandmark,colr,rpincode',',');
},
rtv:function(el){setFormValidation(el,'FormPanel2',document.getElementById('rv').checked);},
ov:function(el){
setFormValidation(el,'FormPanel3',document.getElementById('otv').checked);
EnableDisableFields(el.checked,'oaddr1,oaddr2,oaddr3,olandmark,colo,opincode',',');
},
otv:function(el){setFormValidation(el,'FormPanel3',document.getElementById('ov').checked);},
pv:function(el){
setFormValidation(el,'FormPanel4',false);
EnableDisableFields(el.checked,'paddr1,paddr2,paddr3,plandmark,colp,ppincode',',');
if(!el.checked){document.getElementById('rcp').checked=false;document.getElementById('ocp').checked=false;}
},
refv:function(el){setFormValidation(el,'FormPanel5',false);},
rco:function(el){AutoFill('rco',el.checked ? 1 : 0);},
rcp:function(el){handlePropertyCopy(el,'rcp','ocp');},
ocp:function(el){handlePropertyCopy(el,'ocp','rcp');}
};
function handlePropertyCopy(el,copyType,otherCheckboxId)
{
AutoFill(copyType,el.checked ? 1 : 0);
if(!el.checked) return;
document.getElementById(otherCheckboxId).checked=false;
var property=document.getElementById('pv');
property.checked=true;
HandleClick(property);
}
function setFormValidation(Elem,FormPanel,CounterPartElem)
{
if(Elem.checked || CounterPartElem)
{
UnhideSections(FormPanel+ColDelim, ColDelim);
}
else
{
HideSections(FormPanel);
}
CygnusInitiationValidation.validateVerification(Elem.id);
FireToggleEvents();
}
function AutoFill(Opt,FillMode)
{
var mapping=ADDRESS_COPY_MAPPINGS[Opt];
if(!mapping) return;
if(FillMode==1) CopyDetails(mapping.source,mapping.target);
else if(document.getElementById(mapping.sourceColony).value==document.getElementById(mapping.targetColony).value)
ClearDetails(mapping.target);
}
var ADDRESS_COPY_MAPPINGS={
rco:{
source:["raddr1","raddr2","raddr3","Rcolony","colr","rcity","rlandmark","rpincode","rphone"],
target:["oaddr1","oaddr2","oaddr3","Ocolony","colo","ocity","olandmark","opincode","ophone"],
sourceColony:"Rcolony",targetColony:"Ocolony"
},
rcp:{
source:["raddr1","raddr2","raddr3","Rcolony","colr","rcity","rlandmark","rpincode"],
target:["paddr1","paddr2","paddr3","Pcolony","colp","pcity","plandmark","ppincode"],
sourceColony:"Rcolony",targetColony:"Pcolony"
},
ocp:{
source:["oaddr1","oaddr2","oaddr3","Ocolony","colo","ocity","olandmark","opincode"],
target:["paddr1","paddr2","paddr3","Pcolony","colp","pcity","plandmark","ppincode"],
sourceColony:"Ocolony",targetColony:"Pcolony"
}
};
function ToggleChks(IsVisible,ChildElems)
{
if(IsVisible)
{
ChildElems.forEach(function(id){UnhideSections(id+ColDelim,ColDelim);});
}
else
{
ChildElems.forEach(function(id){HideSections(id);document.getElementById(id).checked=false;});
}
}
function ClearDetails(TargetFields)
{
TargetFields.forEach(function(id){document.getElementById(id).value="";});
}
function CopyDetails(SourceFields,TargetFields)
{
SourceFields.forEach(function(id,index){document.getElementById(TargetFields[index]).value=document.getElementById(id).value;});
}
function AfterOptSelect(ElemToRemove,OprID)
{
FillSameDet(selectedAddr, OprID);
selectedAddr=-1;
ElemToRemove.parentNode.removeChild(ElemToRemove);
}
function ShowAddrOptions(OprID)
{
var optDiv=document.createElement("div");
var Addr="";
optDiv.setAttribute("id","optDiv");
optDiv.setAttribute("class","FormPanel");
optDiv.setAttribute("style","font-family:Tahoma;overflow:visible");
var OptionPanel="<div id='TablePanel' class='tableContainer'><table border='0' cellspacing='0' width='100%' id='cutlist'><thead class='thead'><tr title='Row Title'><td colspan='2'>Available Addresses</td></tr></thead><tbody class='scrollContent'>";
for(var indx=0;indx<SameAddr.length;indx++)
{
OptionPanel=OptionPanel+"<tr><td><input type='radio' name='rb1' id='rb"+indx+"' value='"+indx+"' onclick='selectedAddr=this.value;' /></td>";
OptionPanel=OptionPanel+"<td style='padding-right:5px'>";
for(var cindx=0;cindx<4;cindx++)
{
Addr=Addr+" "+escapeHtml(SameAddr[indx][cindx]);
}
OptionPanel=OptionPanel+""+Addr+"</td></tr>";
Addr="";
}
OptionPanel=OptionPanel+"<tr><td colspan='2'><input type='button' class='button' name='btnok' style='margin-top:5px;float:right' value='OK' id='btnok' accesskey='K' onclick=\"AfterOptSelect(document.getElementById('inptDialog'),"+OprID+");\"";
OptionPanel=OptionPanel+"</tbody></table></div>";
optDiv.innerHTML=OptionPanel;
ShowInputDialog(optDiv,"Select Address","hint","inptDialog");
document.getElementById('rb0').focus();
}
function escapeHtml(value)
{
return String(value == null ? "" : value).replace(/[&<>"']/g, function(character) {
return ({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[character];
});
}
function FillSameDet(AddrIndex,OprID)
{
if(!(AddrIndex < 0))
{
for(var cindx=0;cindx<SameAddr[AddrIndex].length;cindx++)
{
$("#"+AddrElem[OprID][cindx+1]).val((SameAddr[AddrIndex][cindx]));
}
document.getElementById(FocusAfter).focus();
var applicationType=document.getElementById('apptype').value.toUpperCase();
ToggleChks(applicationType!='APPLICANT' && applicationType!='-1',["sradd","soadd","spadd"]);
}
else
{
document.getElementById(AddrElem[OprID][0]).focus();
if(document.getElementById(AddrElem[OprID][0]).type=='checkbox'){document.getElementById(AddrElem[OprID][0]).checked=false;}
}
}
function SelectAddr(OprID)
{
if(SameAddr.length>1)
{
ShowAddrOptions(OprID);
}
else if(SameAddr.length===1)
{
FillSameDet(0,OprID);
}
else
{
FillSameDet(-1,OprID);
}
}
function FindSameDet(Elm,Visit,focAfter)
{
if($("#case_id").val()!='0' && Visit=='A')
{
return;
}
else
{
FocusAfter=focAfter;
var procFlag=true;
if(Elm.type=='checkbox')
{
procFlag=Elm.checked;
}
if(procFlag)
{
var Applno=document.getElementById('applno').value;
if(Applno.length==0)
{
if(Elm.type=='checkbox'){Elm.checked=false;}
CygnusNotifications.show({type:"danger",code:"VLFRM",message:"Please enter application number.",duration:3000});
document.getElementById('applno').focus();
return false;
}
else
{
SameAddr=[];
var oprId=DUPLICATE_OPERATION[Visit];
loadDuplicateDetails(Applno,$("#portfolio_id").val(),oprId);
}
}
}
}
function FindStr(el,elmids)
{
el.value=el.value.split('->')[0];
var skey=el.value.trim().toUpperCase();
if(skey!='UNKNOWN' && skey!='-1')
{
for(var indx=0;indx<elmids.length;indx++)
{
if(document.getElementById(elmids[indx]).value.toUpperCase().search(skey)>-1)
{
return true;
}
}
}
else
{
return true;
}
return false;
}
var ADDRESS_SECTIONS={
r:{verification:"rv",city:"rcity",colony:"colr",colonyId:"Rcolony",addressFields:["raddr2","raddr3"]},
o:{verification:"ov",city:"ocity",colony:"colo",colonyId:"Ocolony",addressFields:["oaddr2","oaddr3"]},
p:{verification:"pv",city:"pcity",colony:"colp",colonyId:"Pcolony",addressFields:["paddr2","paddr3"]}
};
function addressSectionFor(fieldId)
{
var keys=Object.keys(ADDRESS_SECTIONS);
for(var index=0;index<keys.length;index++)
{
var section=ADDRESS_SECTIONS[keys[index]];
if(fieldId==section.city || fieldId==section.colony) return section;
}
return null;
}
function HandleBlur(el)
{
var section=addressSectionFor(el.id);
if(!section) return;
if(el.id==section.city)
{
if(!FindStr(el,section.addressFields))
{
CygnusNotifications.show({type:"danger",code:"1001AREA",message:"Invalid area.",duration:3000});
el.value="-1";
document.getElementById(section.colonyId).value="";
document.getElementById(section.colony).value="";
}
CygnusInitiationValidation.validateField(el);
}
if(el.id==section.colony)
{
if(!FindStr(el,section.addressFields))
{
CygnusNotifications.show({type:"danger",code:"1001AREA",message:"Invalid colony.",duration:3000});
el.value="";
}
var colonyId=document.getElementById(section.colonyId);
if(el.value=='') colonyId.value='';
if(colonyId.value=='') el.value='';
CygnusInitiationValidation.validateField(el);
}
}

View File

@@ -0,0 +1,150 @@
(function (window, document) {
"use strict";
const FORMATS = Object.freeze({
Email: /^\S*\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,8}\b\S*$/,
Numeric: /^\d*$/,
AlphaNumeric: /^[a-zA-Z0-9_*\/\-]*$/,
AlphaSpace: /^[a-zA-Z0-9()\/ &]*$/,
LoanAmount: /^[a-zA-Z0-9. ]*$/,
SplInstruction: /^[a-zA-Z0-9():,#@.\-\/ ]*$/,
Remarks: /^[a-zA-Z0-9,(),:+&#@'.\-\/ ]*$/,
Pincode: /^\d{6}$/,
Phone: /^((\d{6,8}|\d{10}|\d{3}-\d{6,8})([\/](\d{6,8}|\d{10}|\d{3}-\d{6,8})){0,2})$/,
Extension: /^\d{3,4}$/
});
const DATE_PATTERN = /^(\d{1,2})\/(\d{1,2})\/(\d{4})$/;
function sanitize(value, options) {
const multiline = Boolean(options && options.multiline);
let sanitized = String(value == null ? "" : value).replace(/\t/g, "");
if (multiline) {
sanitized = sanitized.replace(/\r\n?/g, "\n").replace(/[^\x20-\x7E\n]/g, "");
} else {
sanitized = sanitized.replace(/[\r\n]/g, "").replace(/[^\x20-\x7E]/g, "");
}
return sanitized.trim();
}
function sanitizeElement(element) {
if (!element || typeof element.value !== "string") return "";
const tagName = element.tagName ? element.tagName.toLowerCase() : "";
const inputType = (element.type || "text").toLowerCase();
const sanitizableInput = tagName === "input" &&
["text", "search", "tel", "email", "url", "password"].includes(inputType);
if (tagName !== "textarea" && !sanitizableInput) return element.value;
const sanitized = sanitize(element.value, { multiline: tagName === "textarea" });
if (element.value !== sanitized) element.value = sanitized;
return sanitized;
}
function valueOf(element) {
return element && typeof element.value === "string" ? element.value.trim() : "";
}
function isEmpty(element) {
const value = valueOf(element);
return value === "" || (element.type === "select-one" && value === "-1");
}
function isDate(value) {
const parts = DATE_PATTERN.exec(value);
if (!parts) return false;
const day = Number(parts[1]);
const month = Number(parts[2]);
const year = Number(parts[3]);
if (year < 1900 || year > 2100 || month < 1 || month > 12) return false;
const date = new Date(year, month - 1, day);
return date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day;
}
function matchesFormat(value, format) {
if (!value || !format || format === "AllowWrong") return true;
const normalized = Object.keys(FORMATS).find((name) => name.toLowerCase() === format.toLowerCase());
if (format.toLowerCase() === "date") return isDate(value);
return normalized ? FORMATS[normalized].test(value) : true;
}
function errorHost(element) {
let current = element.parentNode;
let host = current;
while (current && current !== document.body) {
if ((" " + (current.className || "") + " ").indexOf(" inputcontainer ") !== -1) return current;
current = current.parentNode;
}
return host;
}
function clearError(element) {
if (!element) return;
const icon = document.getElementById("err" + element.id);
if (icon && icon.parentNode) icon.parentNode.removeChild(icon);
element.classList.remove("errtxt");
if (element.parentNode) element.parentNode.classList.remove("errdiv");
element.removeAttribute("aria-invalid");
element.removeAttribute("aria-describedby");
if (typeof element.setCustomValidity === "function") element.setCustomValidity("");
}
function showError(element, message) {
if (!element) return;
clearError(element);
const host = errorHost(element);
const icon = document.createElement("img");
icon.src = "/matrix/images/exclamation.png";
icon.id = "err" + element.id;
icon.alt = message;
icon.title = message;
icon.className = "matrix-validation-error-icon" +
(element.type === "select-one" ? " matrix-validation-error-icon--select" : "");
icon.style.cssText = "position:absolute;right:" + (element.type === "select-one" ? "24px" : "5px") +
";top:50%;width:14px;height:14px;transform:translateY(-50%);z-index:3;pointer-events:none";
host.style.position = "relative";
host.appendChild(icon);
if (element.type === "select-one") element.parentNode.classList.add("errdiv");
else element.classList.add("errtxt");
element.setAttribute("aria-invalid", "true");
element.setAttribute("aria-describedby", icon.id);
if (typeof element.setCustomValidity === "function") element.setCustomValidity(message);
}
function validateElement(element, rule) {
if (!element) return true;
sanitizeElement(element);
if (typeof rule.when === "function" && !rule.when()) {
clearError(element);
return true;
}
const required = typeof rule.required === "function" ? rule.required() : Boolean(rule.required);
let message = "";
if (required && isEmpty(element)) message = rule.requiredMessage || "This field is required.";
else if (!isEmpty(element) && !matchesFormat(valueOf(element), rule.format)) {
message = rule.formatMessage || "Enter a valid value.";
}
if (message) showError(element, message);
else clearError(element);
return message === "";
}
function validateLegacy(element, requiredFlag, format) {
return validateElement(element, { required: requiredFlag === "t", format: format });
}
function validateRules(rules) {
const invalid = [];
Object.keys(rules).forEach(function (id) {
const element = document.getElementById(id);
if (!validateElement(element, rules[id])) invalid.push(element);
});
return { valid: invalid.length === 0, invalid: invalid };
}
window.CygnusFormValidation = Object.freeze({
clearError: clearError,
sanitize: sanitize,
sanitizeElement: sanitizeElement,
validateElement: validateElement,
validateLegacy: validateLegacy,
validateRules: validateRules
});
}(window, document));

View File

@@ -0,0 +1,95 @@
(function (window, document) {
"use strict";
const DEFAULT_DURATION = 7000;
const VALID_TYPES = new Set(["success", "info", "warning", "danger"]);
function getHost() {
let host = document.getElementById("cygnus-notifications");
if (!host) {
host = document.createElement("div");
host.id = "cygnus-notifications";
host.className = "position-fixed top-0 start-50 translate-middle-x p-3";
host.style.cssText = "z-index:1085;max-width:720px;width:calc(100% - 2rem)";
host.setAttribute("aria-live", "polite");
host.setAttribute("aria-atomic", "true");
document.body.append(host);
}
return host;
}
function dismiss(alert) {
const bootstrapAlert = window.bootstrap?.Alert;
if (bootstrapAlert) {
bootstrapAlert.getOrCreateInstance(alert).close();
} else {
alert.remove();
}
}
function show(options) {
const settings = options || {};
const type = VALID_TYPES.has(settings.type) ? settings.type : "info";
const host = getHost();
const alert = document.createElement("div");
alert.className = `alert alert-${type} alert-dismissible fade show shadow-sm`;
alert.setAttribute("role", type === "danger" ? "alert" : "status");
if (settings.code) {
const code = document.createElement("strong");
code.textContent = `${settings.code}: `;
alert.append(code);
}
alert.append(document.createTextNode(settings.message || ""));
if (settings.referenceId) {
const reference = document.createElement("small");
reference.className = "d-block mt-1";
reference.textContent = `Reference: ${settings.referenceId}`;
alert.append(reference);
}
if (settings.dismissible !== false) {
const close = document.createElement("button");
close.type = "button";
close.className = "btn-close";
close.setAttribute("aria-label", "Close");
close.addEventListener("click", () => dismiss(alert));
alert.append(close);
}
if (settings.stack === true) host.append(alert);
else host.replaceChildren(alert);
const duration = settings.duration === undefined ? DEFAULT_DURATION : settings.duration;
if (Number.isFinite(duration) && duration > 0) {
window.setTimeout(() => {
if (alert.isConnected) dismiss(alert);
}, duration);
}
return alert;
}
function clear() {
document.getElementById("cygnus-notifications")?.replaceChildren();
}
function showLegacy(serialized, options) {
const text = String(serialized || "");
const firstSeparator = text.indexOf(":");
const secondSeparator = firstSeparator < 0 ? -1 : text.indexOf(":", firstSeparator + 1);
const settings = Object.assign({}, options);
if (secondSeparator > firstSeparator) {
settings.code = text.slice(0, firstSeparator);
const legacyType = text.slice(firstSeparator + 1, secondSeparator).toLowerCase();
settings.type = legacyType === "error" ? "danger" : legacyType;
settings.message = text.slice(secondSeparator + 1);
} else {
settings.type = settings.type || "danger";
settings.message = text;
}
return show(settings);
}
window.CygnusNotifications = Object.freeze({ show, showLegacy, clear });
}(window, document));

View File

@@ -0,0 +1,91 @@
(function (window) {
"use strict";
const keyRequests = new Map();
const encoder = new TextEncoder();
function toBase64Url(bytes) {
let binary = "";
const view = new Uint8Array(bytes);
for (let offset = 0; offset < view.length; offset += 0x8000) {
binary += String.fromCharCode(...view.subarray(offset, offset + 0x8000));
}
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
}
function fromBase64Url(text) {
const normalized = text.replace(/-/g, "+").replace(/_/g, "/");
const binary = atob(normalized + "=".repeat((4 - normalized.length % 4) % 4));
return Uint8Array.from(binary, (character) => character.charCodeAt(0));
}
function fetchKey(keyUrl) {
if (!keyUrl) {
return Promise.reject(new Error("A payload encryption key URL is required."));
}
if (!keyRequests.has(keyUrl)) {
const request = fetch(keyUrl, {
credentials: "same-origin",
headers: { Accept: "application/json" }
}).then(async (response) => {
const body = await response.json();
if (!response.ok) throw body;
if (!body.keyId || !body.publicKey) {
throw new Error("The payload encryption key response is invalid.");
}
return body;
}).catch((error) => {
keyRequests.delete(keyUrl);
throw error;
});
keyRequests.set(keyUrl, request);
}
return keyRequests.get(keyUrl);
}
async function encrypt(payload, options) {
if (!window.crypto?.subtle) {
throw new Error("Secure payload encryption is not supported by this browser.");
}
const keyInfo = await fetchKey(options?.keyUrl);
const publicKey = await window.crypto.subtle.importKey(
"spki",
fromBase64Url(keyInfo.publicKey),
{ name: "RSA-OAEP", hash: "SHA-256" },
false,
["encrypt"]
);
const aesKey = await window.crypto.subtle.generateKey(
{ name: "AES-GCM", length: 256 }, true, ["encrypt"]
);
const initializationVector = window.crypto.getRandomValues(new Uint8Array(12));
const requestId = window.crypto.randomUUID();
const timestamp = new Date().toISOString();
const additionalData = encoder.encode(`${keyInfo.keyId}|${requestId}|${timestamp}`);
const encryptedPayload = await window.crypto.subtle.encrypt(
{ name: "AES-GCM", iv: initializationVector, additionalData },
aesKey,
encoder.encode(JSON.stringify(payload))
);
const rawKey = await window.crypto.subtle.exportKey("raw", aesKey);
const encryptedKey = await window.crypto.subtle.encrypt(
{ name: "RSA-OAEP" }, publicKey, rawKey
);
return Object.freeze({
keyId: keyInfo.keyId,
encryptedKey: toBase64Url(encryptedKey),
initializationVector: toBase64Url(initializationVector),
encryptedPayload: toBase64Url(encryptedPayload),
requestId,
timestamp
});
}
function clearKeyCache(keyUrl) {
if (keyUrl) keyRequests.delete(keyUrl);
else keyRequests.clear();
}
window.CygnusPayloadCrypto = Object.freeze({ encrypt, clearKeyCache });
}(window));

View File

@@ -91,28 +91,33 @@ function highlightField(el)
else
{
invalidFields=invalidFields+1;
var offset=null;
var width=null;
var iconHost=el.parentNode;
var current=el.parentNode;
while(current && current!==document.body)
{
var classes=" "+(current.className || "")+" ";
if(classes.indexOf(" inputcontainer ")!==-1)
{
iconHost=current;
break;
}
current=current.parentNode;
}
if(el.type=='text' || el.type=='textarea' || el.type=='password')
{
el.setAttribute("class", "textbox errtxt");
offset=$(el).offset();
width=el.offsetWidth;
}
else if(el.type=='select-one')
{
el.parentNode.setAttribute("class", "divselect errdiv");
tmpel=el.parentNode;
offset=$(tmpel).offset();
width=tmpel.offsetWidth;
}
var top=parseInt(offset.top)-5;
var left=parseInt(offset.left)+(width-5);
iconHost.style.position="relative";
var img=document.createElement("img");
img.setAttribute("src","/matrix/images/exclamation.png");
img.setAttribute("style","position:absolute;margin-left:"+left+"px;margin-top:"+top+"px;z-index:3");
img.setAttribute("class", "matrix-validation-error-icon"+(el.type=='select-one' ? " matrix-validation-error-icon--select" : ""));
img.setAttribute("style","position:absolute;right:"+(el.type=='select-one' ? "24px" : "5px")+";top:50%;width:14px;height:14px;transform:translateY(-50%);z-index:3;pointer-events:none");
img.setAttribute("id","err"+el.id);
document.body.appendChild(img);
iconHost.appendChild(img);
}
}

View File

@@ -23,6 +23,16 @@
</properties>
<dependencies>
<dependency>
<groupId>com.cygnus</groupId>
<artifactId>cygnus-lib</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.cygnus</groupId>
<artifactId>cygnus-onprem-db</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.cygnus</groupId>
<artifactId>cygnus-cloud-client</artifactId>

View File

@@ -5,7 +5,7 @@ import com.cygnus.client.CloudIdentityClient;
import java.time.Duration;
import java.util.logging.Level;
import java.util.logging.Logger;
import matrix.nimble.model.Session;
import lib.models.UserSession;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClientResponseException;
@@ -28,7 +28,7 @@ public class CloudAuthenticationGateway {
this.sessionMapper = sessionMapper;
}
public Session authenticate(String loginId, String password) {
public UserSession authenticate(String loginId, String password) {
try {
Duration blockingTimeout = properties.requestTimeout().plusSeconds(1);
return sessionMapper.map(client.authenticate(loginId, password).block(blockingTimeout));

View File

@@ -5,6 +5,7 @@ import com.cygnus.client.model.CloudMenuItem;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.List;
import lib.models.UserSession;
import matrix.nimble.model.Session;
import org.springframework.stereotype.Component;
@@ -20,22 +21,42 @@ public class CloudSessionMapper {
this.menuRenderer = menuRenderer;
}
public Session map(CloudIdentitySession source) {
public UserSession map(CloudIdentitySession source) {
return UserSession.builder()
.userId(source.userId())
.username(source.loginId())
.userDisplayName(source.displayName())
.userGroupId(source.groupId())
.userGroupName(source.groupName())
.branchId(source.branchId())
.branchName(source.branchName())
.branchCode(source.branchCode())
.branchLocation(source.branchLocation())
.companyId(source.companyId())
.companyName(source.companyName())
.companyCode(source.companyCode())
.loginTime(LEGACY_LOGIN_TIME.format(source.loginTime()))
.menuHtml(menuRenderer.render(toLegacyMenu(source.menu())))
.build();
}
/** Temporary projection used by controllers that have not migrated to UserSession yet. */
public Session toLegacy(UserSession source) {
Session target = new Session();
target.setUserID(Short.toString(source.userId()));
target.setUsername(source.loginId());
target.setUserDisplayName(source.displayName());
target.setUserGroupID(Short.toString(source.groupId()));
target.setUserGroupName(source.groupName());
target.setBranchID(Short.toString(source.branchId()));
target.setBranchName(source.branchName());
target.setBranchCode(source.branchCode());
target.setBranchLocation(source.branchLocation());
target.setCompanyID(Short.toString(source.companyId()));
target.setCompanyName(source.companyName());
target.setCompanyCode(source.companyCode());
target.setLoginTime(LEGACY_LOGIN_TIME.format(source.loginTime()));
target.setMenuHtml(menuRenderer.render(toLegacyMenu(source.menu())));
target.setUserID(Short.toString(source.getUserId()));
target.setUsername(source.getUsername());
target.setUserDisplayName(source.getUserDisplayName());
target.setUserGroupID(Short.toString(source.getUserGroupId()));
target.setUserGroupName(source.getUserGroupName());
target.setBranchID(Short.toString(source.getBranchId()));
target.setBranchName(source.getBranchName());
target.setBranchCode(source.getBranchCode());
target.setBranchLocation(source.getBranchLocation());
target.setCompanyID(Short.toString(source.getCompanyId()));
target.setCompanyName(source.getCompanyName());
target.setCompanyCode(source.getCompanyCode());
target.setLoginTime(source.getLoginTime());
target.setMenuHtml(source.getMenuHtml());
return target;
}

View File

@@ -0,0 +1,87 @@
package matrix.nimble.controller;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lib.constants.ApplicationMessage;
import lib.models.MessageDetails;
import lib.models.UserSession;
import matrix.services.commons.CommonErrorService;
import matrix.services.commons.CommonService;
import org.springframework.ui.ModelMap;
/** Shared session and page-authorization workflow for authenticated controllers. */
public abstract class AbstractAuthenticatedController {
private final CommonService commonService;
private final CommonErrorService errorService;
protected AbstractAuthenticatedController(
CommonService commonService,
CommonErrorService errorService) {
this.commonService = commonService;
this.errorService = errorService;
}
protected final PageAuthorization authorizePage(
String pageRoute,
ModelMap model,
HttpSession httpSession,
HttpServletResponse response) {
UserSession session = commonService.getUserSession(httpSession);
if (session == null) {
return denied(model, response, httpSession, ApplicationMessage.SESSION_REQUIRED);
}
if (!commonService.hasPageAccess(session, pageRoute)) {
return denied(model, response, httpSession, ApplicationMessage.ACCESS_DENIED);
}
model.addAttribute(CommonService.USER_SESSION_ATTRIBUTE, session);
return PageAuthorization.granted(session);
}
protected final ApiAuthorization authorizeApiPage(
String pageRoute, HttpSession httpSession) {
UserSession session = commonService.getUserSession(httpSession);
if (session == null) {
return ApiAuthorization.denied(new MessageDetails(ApplicationMessage.SESSION_REQUIRED));
}
if (!commonService.hasPageAccess(session, pageRoute)) {
return ApiAuthorization.denied(new MessageDetails(ApplicationMessage.ACCESS_DENIED));
}
return ApiAuthorization.granted(session);
}
private PageAuthorization denied(
ModelMap model,
HttpServletResponse response,
HttpSession httpSession,
ApplicationMessage error) {
String viewName = errorService.render(
model, response, httpSession, new MessageDetails(error));
return PageAuthorization.denied(viewName);
}
protected record PageAuthorization(UserSession session, String viewName) {
private static PageAuthorization granted(UserSession session) {
return new PageAuthorization(session, null);
}
private static PageAuthorization denied(String viewName) {
return new PageAuthorization(null, viewName);
}
public boolean isGranted() {
return session != null;
}
}
protected record ApiAuthorization(UserSession session, MessageDetails error) {
private static ApiAuthorization granted(UserSession session) {
return new ApiAuthorization(session, null);
}
private static ApiAuthorization denied(MessageDetails error) {
return new ApiAuthorization(null, error);
}
public boolean isGranted() { return session != null; }
}
}

View File

@@ -13,7 +13,6 @@ import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import matrix.nimble.edp.cutoff.model.AutoCutThread;
import matrix.nimble.model.MailboxHandler;
import matrix.nimble.model.Session;
import matrix.nimble.model.UploadHandler;
@@ -40,121 +39,6 @@ import org.springframework.web.multipart.MultipartHttpServletRequest;
@Controller
@SessionAttributes({"Sessvals"})
public class Ajax {
@RequestMapping(value="punchedrecs",method=RequestMethod.GET )
public @ResponseBody String PunchedRecords(@RequestParam String val0,@RequestParam String val1,@RequestParam String val2)
{
val1=(val1.replace(GlobalClass.ColDelim, ","));
String fields="case_id,portfolio_id,mvcode,bank_branch_id,applno,product,loanamount,customername,apptype,category,dob,contactperson,mobileno,raddr1,raddr2,raddr3,rlandmark,Rcolony,rcity,rpincode,rphone,companyname,oaddr1,oaddr2,oaddr3,olandmark,Ocolony,ocity,opincode,department,designation,ophone,extension,paddr1,paddr2,paddr3,plandmark,Pcolony,pcity,ppincode,refname1,refaddress1,refcontactno1,refname2,refaddress2,refcontactno2,rv,rtv,ov,otv,pv,refv,docv,rco,rcp,ocp,specialinst,sradd,soadd,spadd,"+val1+"colr,colo,colp,fathername,bankcode,status,company_id,branch_id,uuid";
DBFunctions DBF=new DBFunctions("1001");
DBF.setProcessFlag(true);
if(val2.trim().length() > 20)
{
val0="uuid='"+val2+"'";
}
else
{
val0="portfolio_id="+val0+" and (cutoffby is null or cutoffby=0)";
}
String response= DBF.FetchRunQuery(24, (val0+GlobalClass.ColDelim+val1+GlobalClass.ColDelim+val2+GlobalClass.ColDelim).split(GlobalClass.ColDelim));
fields=fields.replace(",", GlobalClass.ColDelim);
fields=fields+GlobalClass.RowDelim;
if(DBF.isProcessFlag())
{
response=fields+response;
}
else
{
response=DBF.getErrMsg();
response=fields;
}
return response;
}
@RequestMapping(value="puncheddocrecs",method=RequestMethod.GET )
public @ResponseBody String PunchedDocRecords(@RequestParam String val0,@RequestParam String val1)
{
val1=(val1.replace(GlobalClass.ColDelim, ","));
String fields="case_id,portfolio_id,bank_branch_id,applno,product,loanamount,customername,apptype,category,dob,docv,"+val1+"docs,status,company_id,branch_id,uuid";
DBFunctions DBF=new DBFunctions("1001");
DBF.setProcessFlag(true);
String response= DBF.FetchRunQuery(242, (val0+GlobalClass.ColDelim+val1+GlobalClass.ColDelim+"0"+GlobalClass.ColDelim).split(GlobalClass.ColDelim));
fields=fields.replace(",", GlobalClass.ColDelim);
fields=fields+GlobalClass.RowDelim;
if(DBF.isProcessFlag())
{
response=fields+response;
}
else
{
response=DBF.getErrMsg();
response=fields;
}
return response;
}
//insert into main (portfolio_id,bank_branch_id,mvcode,applno,bankcode,product,loanamount,customername,fathername,apptype,category,dob,contactperson,mobileno,specialinst,rv,sradd,rtv,raddr1,raddr2,raddr3,rlandmark,rcolony,rcity,rpincode,rphone,ov,rco,soadd,otv,companyname,oaddr1,oaddr2,oaddr3,olandmark,ocolony,ocity,opincode,department,designation,ophone,extension,pv,rcp,ocp,spadd,paddr1,paddr2,paddr3,plandmark,pcolony,pcity,ppincode,refv,refname1,refaddress1,refcontactno1,refname2,refaddress2,refcontactno2,docv,field1,field2,field3,field4,field5,field6,field7,field8,field9,field10,field11,field12,dtfield1,dtfield2,dtfield3,dtfield4,dtfield5,uuid,receivedate,addedon,addedby,company_id,branch_id) values (val0,val1,'val2','val3','val4','val5','val6','val7','val8','val9','val10','val11','val12','val13','val14',val15,val16,val17,'val18','val19','val20','val21',val22,'val23','val24','val25',val26,val27,val28,val29,'val30','val31','val32','val33','val34',val35,'val36','val37','val38','val39','val40','val41',val42,val43,val44,val45,'val46','val47','val48','val49',val50,'val51','val52',val53,'val54','val55','val56','val57','val58','val59',val60,'val61','val62','val63','val64','val65','val66','val67','val68','val69','val70','val71','val72','val73','val74','val75','val76','val77','val78','val79','val80',val81,val82,val83)
@RequestMapping(value="updatecase",method=RequestMethod.GET )
public @ResponseBody String UpdateRecords(@RequestParam String val0,@RequestParam String val1,@RequestParam String val2,@RequestParam String val3,@RequestParam String val4,@RequestParam String val5,@RequestParam String val6,@RequestParam String val7)
{
String uuid=GlobalClass.GenerateUUID();
String response="";
DBFunctions dbf=new DBFunctions("1001");
dbf.setProcessFlag(true);
val1=val1.replace("~AmP~", "&");
if(val2.equals("0"))
{
val0="mvcode,portfolio_id,"+val0+"receivedate,uuid,addedon,addedby";
val1="''xmvcodex'',"+val6+","+val1+"''"+GlobalClass.DateTime("yyyy/MM/dd", new java.util.Date())+"'',''"+uuid+"'',''"+GlobalClass.DateTime("yyyy/MM/dd HH:mm:ss", new java.util.Date())+"'',"+val5+"";
val0="insert into main ("+val0+") values ("+val1+")";
String [] Qvals=(val0+GlobalClass.ColDelim+"DOCDETAILS"+GlobalClass.ColDelim+val6+GlobalClass.ColDelim+uuid+GlobalClass.ColDelim+val5+GlobalClass.ColDelim+val4+GlobalClass.ColDelim).split(GlobalClass.ColDelim);
dbf.FetchRunQuery(16, Qvals);
if(dbf.isProcessFlag())
{
response=dbf.getProcResult();
if(val4.equals("1")) {
AutoCutThread autoCut = new AutoCutThread();
String [] result = response.split(GlobalClass.ColDelim);
autoCut.setPortfolioid(val6);
autoCut.setUserid(val5);
autoCut.setUuid(result[2]);
autoCut.start();
}
}
else
{
response=dbf.getErrMsg();
}
}
else
{
String [] fields=val0.split(",");
String [] vals=val1.split(",");
val0="";
for(int indx=0;indx<fields.length;indx++)
{
val0=val0+fields[indx]+"="+vals[indx]+",";
}
val0=val0+"addedon=(case when addedby=0 then ''"+GlobalClass.DateTime("yyyy/MM/dd HH:mm:ss", new java.util.Date())+"'' else addedon end),addedby=(case when addedby=0 then "+val5+" else addedby end),lasteditedon=''"+GlobalClass.DateTime("yyyy/MM/dd HH:mm:ss", new java.util.Date())+"'',lasteditedby="+val5;
vals=(val0+GlobalClass.ColDelim+"DOCDETAILS"+GlobalClass.ColDelim+val3+GlobalClass.ColDelim+val6+GlobalClass.ColDelim+val5+GlobalClass.ColDelim+val4+GlobalClass.ColDelim+val7+GlobalClass.ColDelim).split(GlobalClass.ColDelim);
dbf.FetchRunQuery(25, vals);
if(dbf.isProcessFlag())
{
response="success";
if(val4.equals("1")) {
AutoCutThread autoCut = new AutoCutThread();
String [] result = response.split(GlobalClass.ColDelim);
autoCut.setPortfolioid(val6);
autoCut.setUserid(val5);
autoCut.setUuid(val3);
autoCut.start();
}
}
else
{
response=dbf.getErrMsg();
}
}
return response;
}
@RequestMapping(value="uploadservice",method=RequestMethod.POST )
public @ResponseBody String UploadMNimbleCases(@RequestParam String params)
{
@@ -211,21 +95,6 @@ public class Ajax {
}
return response;
}
@RequestMapping(value="getlocality",method=RequestMethod.POST )
public @ResponseBody String GetLocality(@RequestParam String city, @RequestParam String letters)
{
DBFunctions DBF=new DBFunctions("1001");
DBF.setProcessFlag(true);
String val1="and 1=1";
if(!(city.toUpperCase().equals("-1") || city.toUpperCase().equals("UNKNOWN")))
{
val1="and upper(city)=upper('"+city+"')";
}
String response= DBF.FetchRunQuery(13, (letters.toUpperCase()+GlobalClass.ColDelim+val1+GlobalClass.ColDelim).split(GlobalClass.ColDelim));
response=response.replace(GlobalClass.ColDelim+GlobalClass.RowDelim, GlobalClass.RowDelim);
return response;
}
@RequestMapping(value="listservprovider",method=RequestMethod.POST )
public @ResponseBody String ListServProvider(@RequestParam String city, @RequestParam String letters)
{
@@ -235,16 +104,6 @@ public class Ajax {
response=response.replace(GlobalClass.ColDelim+GlobalClass.RowDelim, GlobalClass.RowDelim);
return response;
}
@RequestMapping(value="findsdet",method=RequestMethod.GET )
public @ResponseBody String FindSameAddr(@RequestParam String val, @RequestParam String val1, @RequestParam String val2)
{
String RecDate=GlobalClass.DateTime("yyyy/MM/dd", new java.util.Date());
DBFunctions DBF=new DBFunctions("1001");
DBF.setProcessFlag(true);
String response= DBF.FetchRunQuery(Integer.parseInt(val2), (val+GlobalClass.ColDelim+val1+GlobalClass.ColDelim+RecDate+GlobalClass.ColDelim).split(GlobalClass.ColDelim));
response=response.replace(GlobalClass.ColDelim+GlobalClass.RowDelim, GlobalClass.RowDelim);
return response;
}
@RequestMapping(value="findbyappno",method=RequestMethod.POST )
public @ResponseBody String FindByApplno(@RequestParam String val0, @RequestParam String val1, @RequestParam String val2, @RequestParam String val3)
{

View File

@@ -0,0 +1,43 @@
package matrix.nimble.controller;
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lib.models.MessageDetails;
import lib.constants.ApplicationMessage;
import matrix.services.commons.CommonErrorService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class ApplicationErrorController {
private final CommonErrorService errorService;
public ApplicationErrorController(CommonErrorService errorService) {
this.errorService = errorService;
}
@RequestMapping("error")
public String error(
ModelMap model,
HttpServletRequest request,
HttpServletResponse response,
HttpSession httpSession) {
int status = status(request);
return errorService.render(model, response, httpSession, details(status));
}
private int status(HttpServletRequest request) {
Object value = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
if (value instanceof Integer status && status >= 400 && status <= 599) {
return status;
}
return HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
}
private MessageDetails details(int status) {
return new MessageDetails(ApplicationMessage.fromHttpStatus(status));
}
}

View File

@@ -1,62 +0,0 @@
package matrix.nimble.controller;
import java.util.HashMap;
import java.util.Map;
import matrix.nimble.utilities.DBFunctions;
import matrix.nimble.utilities.GlobalClass;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping("doc/")
public class DocAjax {
@RequestMapping(value="updcasedocs",method=RequestMethod.POST )
public @ResponseBody String UpdateEmpRecords(@RequestBody String jsonString)
{
String [] qparams=null;
Map<String,String> jsonMap=new HashMap<String, String>();
String [] splitted = (jsonString.replace(":\"\"", ":\"null\"").replace("\",\"","!R0@W@0L!").replace("\":\"","!C@~@L!").replace("{\"", "").replace("\"}", "")).split("!R0@W@0L!");
String query="";
String opron = GlobalClass.DateTime("yyyy/MM/dd",new java.util.Date());
for(int indx=0;indx < splitted.length; indx++)
{
jsonMap.put(splitted[indx].split("!C@~@L!")[0], splitted[indx].split("!C@~@L!")[1]);
}
String opr = jsonMap.get("doc_id").toString().equals("0") ? "ADD DOC":"UPDATE DOC";
if(jsonMap.get("doc_id").toString().equals("0"))
{
query = "INSERT INTO case_documents(uuid, doctype, bank_id, docholdername, serviceprovider,uniqueno, yearmonth,";
query += "city, docvendor, addedby, addedon) values (''"+jsonMap.get("uuid")+"'',"+jsonMap.get("doctype")+",";
query += jsonMap.get("serviceprovider_hidden")+",''"+jsonMap.get("docholdername")+"'',''"+jsonMap.get("serviceprovider")+"'',";
query += "''"+jsonMap.get("uniqueno")+"'',''"+jsonMap.get("yearmonth")+"'',''"+jsonMap.get("city")+"'',";
query += jsonMap.get("vendor_id")+","+jsonMap.get("usid")+",''"+opron+"'')";
}
else
{
query = "update case_documents set doctype=''"+jsonMap.get("doctype")+"'',bank_id="+jsonMap.get("serviceprovider_hidden")+",";
query += "docholdername=''"+jsonMap.get("docholdername")+"'',serviceprovider=''"+jsonMap.get("serviceprovider")+"'',";
query += "uniqueno=''"+jsonMap.get("uniqueno")+"'',yearmonth=''"+jsonMap.get("yearmonth")+"'',";
query += "city=''"+jsonMap.get("city")+"'',docvendor=''"+jsonMap.get("vendor_id")+"'',";
query += "addedby="+jsonMap.get("usid")+",addedon=''"+jsonMap.get("opr")+"'' where doc_id="+jsonMap.get("doc_id");
}
qparams = new String[]{query,jsonMap.get("usid").toString(),opr,opron};
String response="failed";
DBFunctions DBF=new DBFunctions("D001");
DBF.setProcessFlag(true);
DBF.FetchRunQuery(354, qparams);
if(DBF.isProcessFlag())
{
response="{\"status\":\"success\",\"did\":\""+DBF.getProcResult()+"\",\"result\":"+jsonString+"}";
}
else
{
response="{\"status\":\"success\",\"did\":\""+jsonMap.get("doc_id")+"\",\"result\":\""+DBF.getErrMsg()+"\"}";
}
return response;
}
}

View File

@@ -2,8 +2,11 @@ package matrix.nimble.controller;
import matrix.nimble.cloud.identity.CloudAuthenticationException;
import matrix.nimble.cloud.identity.CloudAuthenticationGateway;
import matrix.nimble.cloud.identity.CloudSessionMapper;
import matrix.nimble.model.Login;
import matrix.nimble.model.Session;
import matrix.services.commons.CommonService;
import lib.models.UserSession;
//servlet libraries
import jakarta.servlet.http.HttpServletRequest;
@@ -21,9 +24,16 @@ import org.springframework.web.bind.annotation.SessionAttributes;
@SessionAttributes("Sessvals")
public class SessionController {
private final CloudAuthenticationGateway cloudAuthenticationGateway;
private final CommonService commonService;
private final CloudSessionMapper cloudSessionMapper;
public SessionController(CloudAuthenticationGateway cloudAuthenticationGateway) {
public SessionController(
CloudAuthenticationGateway cloudAuthenticationGateway,
CommonService commonService,
CloudSessionMapper cloudSessionMapper) {
this.cloudAuthenticationGateway = cloudAuthenticationGateway;
this.commonService = commonService;
this.cloudSessionMapper = cloudSessionMapper;
}
@RequestMapping(value="login", method={RequestMethod.GET, RequestMethod.POST})
public String LoginPage(ModelMap model)
@@ -42,13 +52,19 @@ public class SessionController {
return "login";
}
@RequestMapping(value="authenticatelogin",method=RequestMethod.POST )
public String Authenticate(ModelMap model,@ModelAttribute(value="login") Login login)
public String Authenticate(
ModelMap model,
@ModelAttribute(value="login") Login login,
HttpSession httpSession)
{
try {
Session cloudSession = cloudAuthenticationGateway.authenticate(
UserSession userSession = cloudAuthenticationGateway.authenticate(
login.getLoginid(), login.getPassword());
Session cloudSession = cloudSessionMapper.toLegacy(userSession);
model.remove("login");
model.addAttribute("Sessvals", cloudSession);
commonService.storeUserSession(httpSession, userSession);
commonService.storeSession(httpSession, cloudSession);
return "home";
} catch (CloudAuthenticationException exception) {
login.setErrMsg(exception.reason()

View File

@@ -1,161 +0,0 @@
package matrix.nimble.edp.punching.controller;
//servlet libraries
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
//spring libraries
import matrix.nimble.edp.punching.model.CaseDetails;
import matrix.nimble.model.Session;
import matrix.nimble.utilities.ModuleFunctions;
import matrix.nimble.utilities.GlobalClass;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
@Controller
@SessionAttributes({"Sessvals"})
public class CasePucnhing {
@RequestMapping(value="caseadd1",method=RequestMethod.POST )
public String OpenAddCases(ModelMap model,HttpServletRequest request,@ModelAttribute(value="Sessvals") Session Sessvals)
{
CaseDetails caseDetails=new CaseDetails();
caseDetails.setFormMode(1);
caseDetails.setErrMsg("");
model.addAttribute("visibleContents","");
model.addAttribute("caseDetails",caseDetails);
model.addAttribute("branchlist",FillBranchList("0"));
model.addAttribute("prodlist",FillProductList("0"));
model.addAttribute("citylist",FillCityList("0"));
model.addAttribute("typelist",FillApptypeList("0"));
model.addAttribute("doclist",FillDocList("0"));
model.addAttribute("catlist",FillCatList("0"));
model.addAttribute("Sessvals",Sessvals);
model.addAttribute("portlist",FillPortList(Sessvals.getBranchID()));
return "edp/punching/addcases";
}
@RequestMapping(value="casesave",method=RequestMethod.POST )
public String SaveCase(ModelMap model,HttpServletRequest request,@ModelAttribute(value="Sessvals") Session Sessvals,@ModelAttribute(value="caseDetails") CaseDetails caseDet,HttpSession session)
{
String DynamicNsessVals="";
CaseDetails caseDetails=new CaseDetails();
caseDet.setErrCode("1001");
if(caseDet.getDynamicFields()!="")
{
String [] DynamicFields=caseDet.getDynamicFields().split(GlobalClass.ColDelim);
for(int indx=0;indx<DynamicFields.length;indx++)
{
//DynamicNsessVals=DynamicNsessVals+request.getParameter(DynamicFields[indx])+Delimeter.ColDelim;
caseDet.InvokeSetter("set"+DynamicFields[indx], request.getParameter(DynamicFields[indx]));
}
}
if(caseDet.getFormMode()==1 || caseDet.getFormMode()==2)
{
DynamicNsessVals=DynamicNsessVals+""+Sessvals.getUserID()+GlobalClass.ColDelim;
DynamicNsessVals=DynamicNsessVals+""+Sessvals.getCompanyID()+GlobalClass.ColDelim;
DynamicNsessVals=DynamicNsessVals+""+Sessvals.getBranchID();
}
if(!session.getAttribute("UUID").toString().equals(caseDet.getUUID()))
{
caseDetails.setProcessFlag(true);
caseDetails.setErrMsg("");
}
else
{
caseDet.SaveDetails(DynamicNsessVals);
caseDetails.setProcessFlag(caseDet.isProcessFlag());
caseDetails.setErrMsg(caseDet.getErrMsg());
}
String VisibleContents=caseDet.getVisibleContents();
if(caseDetails.isProcessFlag())
{
String UUID=GlobalClass.GenerateUUID();
caseDetails.setUUID(UUID);
session.setAttribute("UUID", UUID);
caseDetails.setErrCode("1001");
caseDetails.setFormMode(caseDet.getFormMode());
caseDetails.setVisibleContents(VisibleContents);
caseDetails.setPortfolioId(caseDet.getPortfolioId());
caseDetails=caseDetails.DynamicHtml(caseDetails,caseDet.getPortfolioId());
caseDetails.setDynamicFields(caseDet.getDynamicFields());
VisibleContents=VisibleContents+""+caseDetails.getDynamicSection();
model.addAttribute("caseDetails",caseDetails);
}
else
{
caseDet=caseDet.DynamicHtml(caseDet,caseDet.getPortfolioId());
VisibleContents=VisibleContents+""+caseDet.getDynamicSection();
model.addAttribute("caseDetails",caseDet);
}
model.addAttribute("visibleContents",VisibleContents);
model.addAttribute("branchlist",FillBranchList(caseDet.getPortfolioId()));
model.addAttribute("prodlist",FillProductList(caseDet.getPortfolioId()));
model.addAttribute("citylist",FillCityList(Sessvals.getBranchID()));
model.addAttribute("typelist",FillApptypeList(Sessvals.getBranchID()));
model.addAttribute("doclist",FillDocList(caseDet.getPortfolioId()));
model.addAttribute("catlist",FillCatList(caseDet.getPortfolioId()));
model.addAttribute("Sessvals",Sessvals);
model.addAttribute("portlist",FillPortList(Sessvals.getBranchID()));
return "edp/punching/addcases";
}
@RequestMapping(value="casedet",method=RequestMethod.POST )
public String GetRequiredData(ModelMap model,HttpServletRequest request,@ModelAttribute(value="Sessvals") Session Sessvals,@ModelAttribute(value="caseDetails") CaseDetails caseDet,HttpSession session)
{
CaseDetails caseDetails = new CaseDetails();
caseDetails.setPortfolioId(caseDet.getPortfolioId());
caseDetails.setErrCode("1001");
String UUID=GlobalClass.GenerateUUID();
caseDetails.setUUID(UUID);
session.setAttribute("UUID", UUID);
caseDetails.setFormMode(caseDet.getFormMode());
caseDetails=caseDetails.DynamicHtml(caseDetails,caseDet.getPortfolioId());
String VisibleContents=(new ModuleFunctions("1001").GetDDHashString(10, ("10"+GlobalClass.ColDelim+caseDet.getPortfolioId()).split(GlobalClass.ColDelim))).replace(GlobalClass.RowDelim, "");
caseDetails.setVisibleContents(VisibleContents);
VisibleContents=(VisibleContents+""+caseDetails.getDynamicSection()).replace(GlobalClass.ColDelim+"null", "");
model.addAttribute("visibleContents",VisibleContents);
model.addAttribute("caseDetails",caseDetails);
model.addAttribute("portlist",Sessvals.getBranchID());
model.addAttribute("branchlist",FillBranchList(caseDet.getPortfolioId()));
model.addAttribute("prodlist",FillProductList(caseDet.getPortfolioId()));
model.addAttribute("citylist",FillCityList(Sessvals.getBranchID()));
model.addAttribute("typelist",FillApptypeList(Sessvals.getBranchID()));
model.addAttribute("doclist",FillDocList(caseDet.getPortfolioId()));
model.addAttribute("catlist",FillCatList(caseDet.getPortfolioId()));
model.addAttribute("Sessvals",Sessvals);
model.addAttribute("portlist",FillPortList(Sessvals.getBranchID()));
return "edp/punching/addcases";
}
public String [][] FillPortList(String BranchId)
{
return new ModuleFunctions("1001").GetResultArray(3,(BranchId+GlobalClass.ColDelim).split(GlobalClass.ColDelim));
}
public String [][] FillCityList(String BranchID)
{
return new ModuleFunctions("1001").GetResultArray(6,BranchID.split(GlobalClass.ColDelim));
}
public String [][] FillApptypeList(String BranchID)
{
return new ModuleFunctions("1001").GetResultArray(8,BranchID.split(GlobalClass.ColDelim));
}
public String [][] FillCatList(String PortfolioID)
{
return new ModuleFunctions("1001").GetResultArray(9,PortfolioID.split(GlobalClass.ColDelim));
}
public String [][] FillDocList(String PortfolioID)
{
return new ModuleFunctions("1001").GetResultArray(7,PortfolioID.split(GlobalClass.ColDelim));
}
public String [][] FillBranchList(String PortfolioID)
{
return new ModuleFunctions("1001").GetResultArray(4,PortfolioID.split(GlobalClass.ColDelim));
}
public String [][] FillProductList(String PortfolioID)
{
return new ModuleFunctions("1001").GetResultArray(5,PortfolioID.split(GlobalClass.ColDelim));
}
}

View File

@@ -1,60 +0,0 @@
package matrix.nimble.edp.punching.controller;
import java.util.HashMap;
import jakarta.servlet.http.HttpServletRequest;
import matrix.nimble.edp.punching.model.CaseGrid;
import matrix.nimble.model.Session;
import matrix.nimble.utilities.GlobalClass;
import matrix.nimble.utilities.ModuleFunctions;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.SessionAttributes;
@Controller
@SessionAttributes({"Sessvals"})
public class EditCasesGrid {
@RequestMapping(value="editgrid",method=RequestMethod.POST )
public String OpenEditGrid(ModelMap model,HttpServletRequest request,@ModelAttribute(value="Sessvals") Session Sessvals)
{
String [][]CaseList=null;
CaseGrid CG=new CaseGrid();
model.addAttribute("Sessvals",Sessvals);
model.addAttribute("caseList",CaseList);
model.addAttribute("caseGrid",CG);
model.addAttribute("portlist",FillPortList(Sessvals.getBranchID(),Sessvals.getUserID()));
return "edp/punching/editcases";
}
@RequestMapping(value="caselist",method=RequestMethod.POST)
public String ListCases(ModelMap model,HttpServletRequest request,@ModelAttribute(value="Sessvals") Session Sessvals,@ModelAttribute(value="caseGrid") CaseGrid caseGrid)
{
CaseGrid CG=new CaseGrid();
CG.setErrCode("1002");
CG.setPortfolioId(caseGrid.getPortfolioId());
String [][]CaseList=CG.FillCaseList(caseGrid.getPortfolioId(), Sessvals.getBranchID());
if(CG.isProcessFlag())
{
model.addAttribute("caseList",CaseList);
model.addAttribute("caseGrid",CG);
}
else
{
caseGrid.setErrMsg(CG.getErrMsg());
model.addAttribute("caseList",CaseList);
model.addAttribute("caseGrid",caseGrid);
}
model.addAttribute("Sessvals",Sessvals);
model.addAttribute("portlist",FillPortList(Sessvals.getBranchID(),Sessvals.getUserID()));
return "edp/punching/editcases";
}
public String [][] FillPortList(String BranchId,String userId)
{
return new ModuleFunctions("1002").GetResultArray(249,(BranchId+GlobalClass.ColDelim+userId+GlobalClass.ColDelim).split(GlobalClass.ColDelim));
}
}

View File

@@ -1,278 +0,0 @@
package matrix.nimble.edp.punching.controller;
//servlet libraries
import java.net.URLDecoder;
import jakarta.servlet.http.HttpServletRequest;
//spring libraries
import matrix.nimble.edp.punching.model.PunchingHandler;
import matrix.nimble.model.Session;
import matrix.nimble.utilities.CommonFunctions;
import matrix.nimble.utilities.GlobalClass;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
@Controller
@SessionAttributes({"Sessvals"})
public class Punching {
@RequestMapping(value="initview",method=RequestMethod.POST )
public String InitializeScreen(ModelMap model,HttpServletRequest request,@ModelAttribute(value="Sessvals") Session Sessvals)
{
PunchingHandler PH=new PunchingHandler();
PH.setErrCode("1001");
model.addAttribute("visiblecontents","");
model.addAttribute("branchlist",null);
model.addAttribute("prodlist",null);
model.addAttribute("citylist",null);
model.addAttribute("typelist",null);
model.addAttribute("doclist",null);
model.addAttribute("catlist",null);
model.addAttribute("portfolio_id","-1");
model.addAttribute("Sessvals",Sessvals);
PH.GetDDValues(3, Sessvals.getBranchID().split(GlobalClass.ColDelim));
model.addAttribute("portlist",PH.getOptionvals());
model.addAttribute("formmode",0);
model.addAttribute("stat",true);
model.addAttribute("duuid","xxx");
model.addAttribute("msg","");
return "edp/punching/initcase";
}
@RequestMapping(value="initdocview",method=RequestMethod.POST )
public String InitDocScreen(ModelMap model,HttpServletRequest request,@ModelAttribute(value="Sessvals") Session Sessvals)
{
PunchingHandler PH=new PunchingHandler();
PH.setErrCode("1901");
model.addAttribute("branchlist",null);
model.addAttribute("prodlist",null);
model.addAttribute("typelist",null);
model.addAttribute("doclist",null);
model.addAttribute("catlist",null);
model.addAttribute("portfolio_id","-1");
model.addAttribute("Sessvals",Sessvals);
PH.GetDDValues(240, Sessvals.getBranchID().split(GlobalClass.ColDelim));
model.addAttribute("portlist",PH.getOptionvals());
model.addAttribute("formmode",0);
model.addAttribute("stat",true);
model.addAttribute("msg","");
return "edp/punching/initdocs";
}
@RequestMapping(value="docadd",method=RequestMethod.POST )
public String PunchDocs(ModelMap model,HttpServletRequest request,@ModelAttribute(value="Sessvals") Session Sessvals)
{
String msg="";
PunchingHandler PH=new PunchingHandler();
CommonFunctions comFunc=new CommonFunctions();
PH.setErrCode("1901");
PH.setPortfolioid(request.getParameter("portfolio_id"));
PH.setProcessFlag(true);
PH.DocDynamicHtml();
if(PH.isProcessFlag())
{
model.addAttribute("dynamichtml",PH.getDynamicpanel());
model.addAttribute("dynamicfields",PH.getDynamicfields());
model.addAttribute("docdynamichtml",PH.getDocdynamicpanel());
model.addAttribute("docdynamicfields",PH.getDocdynamicfields());
}
else
{
msg=PH.getErrMsg();
}
PH.GetDDValues(240, Sessvals.getBranchID().split(GlobalClass.ColDelim));
model.addAttribute("portlist",PH.getOptionvals());
PH.GetDDValues(4, PH.getPortfolioid().split(GlobalClass.ColDelim));
model.addAttribute("branchlist",PH.getOptionvals());
PH.GetDDValues(5, (Sessvals.getBranchID()+GlobalClass.ColDelim+"op.description='DOCUMENT' or op.description='APPTYPE'"+GlobalClass.ColDelim).split(GlobalClass.ColDelim));
if(PH.getOptionvals()!=null)
{
model.addAttribute("typelist",comFunc.GetSubArray("APPTYPE", 2, PH.getOptionvals()));
}
else
{
model.addAttribute("typelist",null);
}
PH.GetDDValues(241, PH.getPortfolioid().split(GlobalClass.ColDelim));
model.addAttribute("doclist",PH.getOptionvals());
PH.GetDDValues(70, (PH.getPortfolioid()+GlobalClass.ColDelim+"op.description='CATEGORY' or op.description='PRODUCT'"+GlobalClass.ColDelim).split(GlobalClass.ColDelim));
if(PH.getOptionvals()!=null)
{
model.addAttribute("prodlist",comFunc.GetSubArray("PRODUCT", 2, PH.getOptionvals()));
model.addAttribute("catlist",comFunc.GetSubArray("CATEGORY", 2, PH.getOptionvals()));
}
else
{
model.addAttribute("prodlist",null);
model.addAttribute("catlist",null);
}
model.addAttribute("portfolio_id",PH.getPortfolioid());
model.addAttribute("usid",Sessvals.getUserID());
model.addAttribute("Sessvals",Sessvals);
model.addAttribute("formmode",1);
model.addAttribute("stat",PH.isProcessFlag());
model.addAttribute("msg",msg);
return "edp/punching/initdocs";
}
@RequestMapping(value="addeditdoc",method=RequestMethod.POST )
public String AddEditDocs(@RequestParam String val0,@RequestParam String val1,@RequestParam String val2,@RequestParam String val3,@RequestParam String val4,@RequestParam String val5,@RequestParam String val6,@RequestParam String val7,@RequestParam String val8,@RequestParam String val9,@RequestParam String val10)
{
String retval="success";
try
{
//System.out.println(URLDecoder.decode(val0,"UTF-8"));
//System.out.println(URLDecoder.decode(val1,"UTF-8"));
//System.out.println(URLDecoder.decode(val2,"UTF-8"));
//System.out.println(URLDecoder.decode(val3,"UTF-8"));
//System.out.println(URLDecoder.decode(val4,"UTF-8"));
//System.out.println(URLDecoder.decode(val6,"UTF-8"));
//System.out.println(URLDecoder.decode(val7,"UTF-8"));
//System.out.println(URLDecoder.decode(val8,"UTF-8"));
//System.out.println(URLDecoder.decode(val9,"UTF-8"));
//System.out.println(URLDecoder.decode(val10,"UTF-8"));
PunchingHandler PH=new PunchingHandler();
PH.setErrCode("1902");
PH.setProcessFlag(true);
PH.AddEditDocs(val0, val1, val2, val3, val4, val6, val7, val8, val9, val10);
}catch(Exception exce)
{
retval=exce.getMessage();
}
return retval;
}
@RequestMapping(value="caseadd",method=RequestMethod.POST )
public String PunchCase(ModelMap model,HttpServletRequest request,@ModelAttribute(value="Sessvals") Session Sessvals)
{
String msg="";
PunchingHandler PH=new PunchingHandler();
CommonFunctions comFunc=new CommonFunctions();
PH.setErrCode("1001");
PH.setPortfolioid(request.getParameter("portfolio_id"));
PH.setProcessFlag(true);
PH.DynamicHtml("10");
if(PH.isProcessFlag())
{
model.addAttribute("dynamicfields",PH.getDynamicfields());
if(PH.isProcessFlag())
{
model.addAttribute("visiblecontents",(PH.GetVisibleSections()+""+PH.getDynamicsection()).replace("null", ""));
model.addAttribute("dynamichtml",PH.getDynamicpanel());
}
else
{
msg=PH.getErrMsg();
}
}
else
{
msg=PH.getErrMsg();
}
PH.GetDDValues(3, Sessvals.getBranchID().split(GlobalClass.ColDelim));
model.addAttribute("portlist",PH.getOptionvals());
PH.GetDDValues(4, PH.getPortfolioid().split(GlobalClass.ColDelim));
model.addAttribute("branchlist",PH.getOptionvals());
PH.GetDDValues(5, (Sessvals.getBranchID()+GlobalClass.ColDelim+"op.description='CITY' or op.description='APPTYPE'"+GlobalClass.ColDelim).split(GlobalClass.ColDelim));
if(PH.getOptionvals()!=null)
{
model.addAttribute("citylist",comFunc.GetSubArray("CITY", 2, PH.getOptionvals()));
model.addAttribute("typelist",comFunc.GetSubArray("APPTYPE", 2, PH.getOptionvals()));
}
else
{
model.addAttribute("citylist",null);
model.addAttribute("typelist",null);
}
PH.GetDDValues(70, (PH.getPortfolioid()+GlobalClass.ColDelim+"op.description='CATEGORY' or op.description='PRODUCT'"+GlobalClass.ColDelim).split(GlobalClass.ColDelim));
if(PH.getOptionvals()!=null)
{
model.addAttribute("prodlist",comFunc.GetSubArray("PRODUCT", 2, PH.getOptionvals()));
model.addAttribute("catlist",comFunc.GetSubArray("CATEGORY", 2, PH.getOptionvals()));
}
else
{
model.addAttribute("prodlist",null);
model.addAttribute("catlist",null);
}
model.addAttribute("portfolio_id",PH.getPortfolioid());
model.addAttribute("doclist",null);
model.addAttribute("usid",Sessvals.getUserID());
model.addAttribute("duuid","xxx");
model.addAttribute("Sessvals",Sessvals);
model.addAttribute("formmode",1);
model.addAttribute("stat",PH.isProcessFlag());
model.addAttribute("msg",msg);
return "edp/punching/initcase";
}
@RequestMapping(value="caseedit",method=RequestMethod.POST )
public String EditCase(ModelMap model,HttpServletRequest request,@ModelAttribute(value="Sessvals") Session Sessvals)
{
String msg="";
PunchingHandler PH=new PunchingHandler();
CommonFunctions comFunc=new CommonFunctions();
PH.setErrCode("1001");
PH.setPortfolioid(request.getParameter("PortfolioId"));
PH.setProcessFlag(true);
PH.DynamicHtml("10");
if(PH.isProcessFlag())
{
model.addAttribute("dynamicfields",PH.getDynamicfields());
if(PH.isProcessFlag())
{
model.addAttribute("visiblecontents",(PH.GetVisibleSections()+""+PH.getDynamicsection()).replace("null", ""));
model.addAttribute("dynamichtml",PH.getDynamicpanel());
}
else
{
msg=PH.getErrMsg();
}
}
else
{
msg=PH.getErrMsg();
}
PH.GetDDValues(3, Sessvals.getBranchID().split(GlobalClass.ColDelim));
model.addAttribute("portlist",PH.getOptionvals());
PH.GetDDValues(4, PH.getPortfolioid().split(GlobalClass.ColDelim));
model.addAttribute("branchlist",PH.getOptionvals());
PH.GetDDValues(5, (Sessvals.getBranchID()+GlobalClass.ColDelim+"op.description='CITY' or op.description='APPTYPE'"+GlobalClass.ColDelim).split(GlobalClass.ColDelim));
if(PH.getOptionvals()!=null)
{
model.addAttribute("citylist",comFunc.GetSubArray("CITY", 2, PH.getOptionvals()));
model.addAttribute("typelist",comFunc.GetSubArray("APPTYPE", 2, PH.getOptionvals()));
}
else
{
model.addAttribute("citylist",null);
model.addAttribute("typelist",null);
}
PH.GetDDValues(70, (PH.getPortfolioid()+GlobalClass.ColDelim+"op.description='CATEGORY' or op.description='PRODUCT'"+GlobalClass.ColDelim).split(GlobalClass.ColDelim));
if(PH.getOptionvals()!=null)
{
model.addAttribute("prodlist",comFunc.GetSubArray("PRODUCT", 2, PH.getOptionvals()));
model.addAttribute("catlist",comFunc.GetSubArray("CATEGORY", 2, PH.getOptionvals()));
}
else
{
model.addAttribute("prodlist",null);
model.addAttribute("catlist",null);
}
model.addAttribute("portfolio_id",PH.getPortfolioid());
model.addAttribute("doclist",null);
model.addAttribute("usid",Sessvals.getUserID());
model.addAttribute("Sessvals",Sessvals);
model.addAttribute("formmode",2);
model.addAttribute("duuid",request.getParameter("uuid"));
model.addAttribute("stat",PH.isProcessFlag());
model.addAttribute("msg",msg);
return "edp/punching/initcase";
}
}

View File

@@ -0,0 +1,289 @@
package matrix.nimble.edp.punching.controllers;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import jakarta.servlet.http.HttpSession;
import jakarta.servlet.http.HttpServletResponse;
import matrix.nimble.controller.AbstractAuthenticatedController;
import lib.models.UserSession;
import matrix.services.commons.CommonService;
import matrix.services.edp.PunchingService;
import matrix.services.commons.CommonErrorService;
import lib.models.CasePunching;
import lib.models.ApplicationDetails;
import lib.models.ApiResponse;
import lib.models.ApplicationSaveData;
import lib.models.ApplicationSaveResult;
import lib.models.CaseSaveRequest;
import lib.models.MessageDetails;
import lib.models.PunchedRecordsData;
import lib.models.DuplicateDetailsData;
import lib.models.LocalityData;
import matrix.nimble.edp.punching.model.CaseGrid;
import lib.constants.ApplicationMessage;
import matrix.nimble.security.PayloadCryptoService;
import lib.exceptions.ApplicationException;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
@Controller
public class PunchingController extends AbstractAuthenticatedController {
private static final Logger LOGGER = Logger.getLogger(PunchingController.class.getName());
private static final String INIT_VIEW_ROUTE = "initview";
private static final String CASE_ADD_ROUTE = "caseadd";
private static final String CASE_EDIT_ROUTE = "caseedit";
private static final String DUPLICATE_DETAILS_ROUTE = "findsdet";
private static final String LOCALITY_ROUTE = "getlocality";
private static final String EDIT_GRID_ROUTE = "editgrid";
private final PunchingService punchingService;
private final PayloadCryptoService cryptoService;
public PunchingController(CommonService commonService, CommonErrorService errorService,
PunchingService punchingService, PayloadCryptoService cryptoService) {
super(commonService, errorService);
this.punchingService = punchingService;
this.cryptoService = cryptoService;
}
@RequestMapping(value = "payload-key", method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public ResponseEntity<?> caseSaveKey(HttpSession httpSession) {
ApiAuthorization authorization = authorizeApiPage(INIT_VIEW_ROUTE, httpSession);
if (!authorization.isGranted()) return error(authorization.error());
return ResponseEntity.ok(Map.of(
"keyId", cryptoService.keyId(),
"algorithm", "RSA-OAEP-256",
"publicKey", cryptoService.encodedPublicKey()));
}
@RequestMapping(value = "punchedrecs", method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public ResponseEntity<ApiResponse<PunchedRecordsData>> punchedRecords(
@RequestParam("portfolioId") Short portfolioId,
@RequestParam(value = "documentCaseId", required = false) String documentCaseId,
HttpSession httpSession) {
ApiAuthorization authorization = authorizeApiPage(INIT_VIEW_ROUTE, httpSession);
if (!authorization.isGranted()) {
return ResponseEntity.status(authorization.error().getHttpStatus())
.body(ApiResponse.failure(authorization.error()));
}
try {
PunchedRecordsData data = punchingService.loadPunchedRecords(
portfolioId, documentCaseId, authorization.session());
return ResponseEntity.ok(ApiResponse.success(
data, new MessageDetails(ApplicationMessage.APPLICATIONS_LOADED)));
} catch (ApplicationException exception) {
LOGGER.log(Level.WARNING, "Punched records were rejected", exception);
MessageDetails details = new MessageDetails(exception.getApplicationMessage());
return ResponseEntity.status(details.getHttpStatus()).body(ApiResponse.failure(details));
} catch (RuntimeException exception) {
LOGGER.log(Level.SEVERE, "Unable to load punched records", exception);
MessageDetails details = new MessageDetails(ApplicationMessage.INTERNAL_SERVER_ERROR);
return ResponseEntity.status(details.getHttpStatus()).body(ApiResponse.failure(details));
}
}
@RequestMapping(value = DUPLICATE_DETAILS_ROUTE, method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public ResponseEntity<ApiResponse<DuplicateDetailsData>> findDuplicateDetails(
@RequestParam("applicationNumber") String applicationNumber,
@RequestParam("portfolioId") Short portfolioId,
@RequestParam("queryId") Integer queryId,
HttpSession httpSession) {
ApiAuthorization authorization = authorizeApiPage(INIT_VIEW_ROUTE, httpSession);
if (!authorization.isGranted()) {
return ResponseEntity.status(authorization.error().getHttpStatus())
.body(ApiResponse.failure(authorization.error()));
}
try {
DuplicateDetailsData data = punchingService.findDuplicateDetails(
applicationNumber, portfolioId, queryId, authorization.session());
return ResponseEntity.ok(ApiResponse.success(
data, new MessageDetails(ApplicationMessage.APPLICATIONS_LOADED)));
} catch (ApplicationException exception) {
LOGGER.log(Level.WARNING, "Duplicate detail search was rejected", exception);
MessageDetails details = new MessageDetails(exception.getApplicationMessage());
return ResponseEntity.status(details.getHttpStatus()).body(ApiResponse.failure(details));
} catch (RuntimeException exception) {
LOGGER.log(Level.SEVERE, "Unable to search duplicate details", exception);
MessageDetails details = new MessageDetails(ApplicationMessage.INTERNAL_SERVER_ERROR);
return ResponseEntity.status(details.getHttpStatus()).body(ApiResponse.failure(details));
}
}
@RequestMapping(value = LOCALITY_ROUTE, method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public ResponseEntity<ApiResponse<LocalityData>> findLocalities(
@RequestParam("city") String city,
@RequestParam("letters") String letters,
HttpSession httpSession) {
ApiAuthorization authorization = authorizeApiPage(INIT_VIEW_ROUTE, httpSession);
if (!authorization.isGranted()) {
return ResponseEntity.status(authorization.error().getHttpStatus())
.body(ApiResponse.failure(authorization.error()));
}
try {
LocalityData data = punchingService.findLocalities(city, letters, authorization.session());
return ResponseEntity.ok(ApiResponse.success(
data, new MessageDetails(ApplicationMessage.APPLICATIONS_LOADED)));
} catch (ApplicationException exception) {
LOGGER.log(Level.WARNING, "Locality search was rejected", exception);
MessageDetails details = new MessageDetails(exception.getApplicationMessage());
return ResponseEntity.status(details.getHttpStatus()).body(ApiResponse.failure(details));
} catch (RuntimeException exception) {
LOGGER.log(Level.SEVERE, "Unable to search localities", exception);
MessageDetails details = new MessageDetails(ApplicationMessage.INTERNAL_SERVER_ERROR);
return ResponseEntity.status(details.getHttpStatus()).body(ApiResponse.failure(details));
}
}
@RequestMapping(value = "application-save", method = RequestMethod.POST,
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public ResponseEntity<ApiResponse<ApplicationSaveData>> saveApplication(
@RequestBody CaseSaveRequest request, HttpSession httpSession) {
ApiAuthorization authorization = authorizeApiPage(INIT_VIEW_ROUTE, httpSession);
if (!authorization.isGranted()) return applicationError(authorization.error());
try {
ApplicationDetails details = cryptoService.decrypt(request, ApplicationDetails.class);
ApplicationSaveResult saved = punchingService.saveApplication(details, authorization.session());
return ResponseEntity.ok(ApiResponse.success(
new ApplicationSaveData(saved.getOperation(), saved.getApplicationId(), saved.getMvCode()),
new MessageDetails(ApplicationMessage.APPLICATION_SAVED)));
} catch (ApplicationException exception) {
LOGGER.log(Level.WARNING, "Application save was rejected", exception);
return applicationError(new MessageDetails(exception.getApplicationMessage()));
} catch (RuntimeException exception) {
LOGGER.log(Level.SEVERE, "Unexpected case-save failure", exception);
return applicationError(new MessageDetails(ApplicationMessage.APPLICATION_SAVE_FAILED));
}
}
private ResponseEntity<?> error(MessageDetails details) {
return ResponseEntity.status(details.getHttpStatus()).body(details);
}
private ResponseEntity<ApiResponse<ApplicationSaveData>> applicationError(MessageDetails details) {
return ResponseEntity.status(details.getHttpStatus())
.body(ApiResponse.failure(details));
}
@RequestMapping(value = INIT_VIEW_ROUTE, method = RequestMethod.POST)
public String InitializeScreen(
ModelMap model,
HttpSession httpSession,
HttpServletResponse response) {
PageAuthorization authorization = authorizePage(
INIT_VIEW_ROUTE, model, httpSession, response);
if (!authorization.isGranted()) {
return authorization.viewName();
}
UserSession userSession = authorization.session();
model.addAttribute("model", punchingService.init(
userSession.getBranchId(), userSession.getUserId(), null, null));
return "edp/punching/initcase";
}
@RequestMapping(value = CASE_ADD_ROUTE, method = RequestMethod.POST)
public String prepareNewApplication(
@ModelAttribute("model") CasePunching submitted,
ModelMap model,
HttpSession httpSession,
HttpServletResponse response) {
PageAuthorization authorization = authorizePage(
INIT_VIEW_ROUTE, model, httpSession, response);
if (!authorization.isGranted()) {
return authorization.viewName();
}
UserSession session = authorization.session();
model.addAttribute("model", punchingService.prepareNewApplication(
submitted, session.getBranchId(), session.getCompanyId(), session.getUserId()));
return "edp/punching/initcase";
}
@RequestMapping(value = CASE_EDIT_ROUTE, method = RequestMethod.POST)
public String prepareApplicationEdit(
@RequestParam("PortfolioId") Short portfolioId,
@RequestParam("uuid") String documentCaseId,
ModelMap model,
HttpSession httpSession,
HttpServletResponse response) {
PageAuthorization authorization = authorizePage(
INIT_VIEW_ROUTE, model, httpSession, response);
if (!authorization.isGranted()) {
return authorization.viewName();
}
UserSession session = authorization.session();
model.addAttribute("model", punchingService.prepareApplicationEdit(
portfolioId, documentCaseId, session.getBranchId(),
session.getCompanyId(), session.getUserId()));
return "edp/punching/initcase";
}
@RequestMapping(value = EDIT_GRID_ROUTE, method = RequestMethod.POST)
public String openEditGrid(
ModelMap model,
HttpSession httpSession,
HttpServletResponse response) {
PageAuthorization authorization = authorizePage(
EDIT_GRID_ROUTE, model, httpSession, response);
if (!authorization.isGranted()) {
return authorization.viewName();
}
populateEditGrid(model, new CaseGrid(), authorization.session(), false);
return "edp/punching/editcases";
}
@RequestMapping(value = "caselist", method = RequestMethod.POST)
public String listEditableCases(
@ModelAttribute("caseGrid") CaseGrid caseGrid,
ModelMap model,
HttpSession httpSession,
HttpServletResponse response) {
PageAuthorization authorization = authorizePage(
EDIT_GRID_ROUTE, model, httpSession, response);
if (!authorization.isGranted()) {
return authorization.viewName();
}
populateEditGrid(model, caseGrid, authorization.session(), true);
return "edp/punching/editcases";
}
private void populateEditGrid(
ModelMap model, CaseGrid caseGrid, UserSession session, boolean loadCases) {
Short portfolioId = selectedPortfolio(caseGrid);
model.addAttribute("caseGrid", caseGrid);
model.addAttribute("portlist", punchingService.loadEditCasePortfolios(session));
model.addAttribute("caseList", loadCases && portfolioId != null
? punchingService.loadEditableCases(portfolioId, session)
: java.util.List.of());
}
private Short selectedPortfolio(CaseGrid caseGrid) {
try {
short portfolioId = Short.parseShort(caseGrid.getPortfolioId());
return portfolioId > 0 ? portfolioId : null;
} catch (NumberFormatException | NullPointerException ignored) {
return null;
}
}
}

View File

@@ -1,9 +1,5 @@
package matrix.nimble.edp.punching.model;
import matrix.nimble.utilities.DBFunctions;
import matrix.nimble.utilities.GlobalClass;
import matrix.nimble.utilities.StringFunctions;
public class CaseGrid {
private String ErrMsg;
private String ErrDesc;
@@ -48,23 +44,4 @@ public class CaseGrid {
public void setCaseID(String caseID) {
CaseID = caseID;
}
public String[][] FillCaseList(String PortfolioID,String CompBranchId)
{
String [][]CaseList=null;
DBFunctions DBF=new DBFunctions(getErrCode());
DBF.setProcessFlag(true);
String ResultData=DBF.FetchRunQuery(23, (PortfolioID+GlobalClass.ColDelim+CompBranchId+GlobalClass.ColDelim).split(GlobalClass.ColDelim));
if(DBF.isProcessFlag())
{
setProcessFlag(DBF.isProcessFlag());
CaseList=new StringFunctions(getErrCode()).ConverTo2DArray(ResultData, GlobalClass.RowDelim, GlobalClass.ColDelim);
}
else
{
setProcessFlag(false);
setErrMsg(DBF.getErrMsg());
setErrDesc(DBF.getErrDesc());
}
return CaseList;
}
}

View File

@@ -1,88 +0,0 @@
package matrix.nimble.edp.punching.model;
public class DocDetails {
private String portfolioid;
private String bankbranchid;
private String applno;
private String customername;
private String product;
private String apptype;
private String category;
private String loanamount;
private String dob;
private String caseid;
private String uuid;
private int formmode;
public String getPortfolioid() {
return portfolioid;
}
public void setPortfolioid(String portfolioid) {
this.portfolioid = portfolioid;
}
public String getBankbranchid() {
return bankbranchid;
}
public void setBankbranchid(String bankbranchid) {
this.bankbranchid = bankbranchid;
}
public String getApplno() {
return applno;
}
public void setApplno(String applno) {
this.applno = applno;
}
public String getCustomername() {
return customername;
}
public void setCustomername(String customername) {
this.customername = customername;
}
public String getProduct() {
return product;
}
public void setProduct(String product) {
this.product = product;
}
public String getApptype() {
return apptype;
}
public void setApptype(String apptype) {
this.apptype = apptype;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public String getLoanamount() {
return loanamount;
}
public void setLoanamount(String loanamount) {
this.loanamount = loanamount;
}
public String getDob() {
return dob;
}
public void setDob(String dob) {
this.dob = dob;
}
public String getCaseid() {
return caseid;
}
public void setCaseid(String caseid) {
this.caseid = caseid;
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
public int getFormmode() {
return formmode;
}
public void setFormmode(int formmode) {
this.formmode = formmode;
}
}

View File

@@ -1,12 +1,5 @@
package matrix.nimble.edp.punching.model;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.collections.FactoryUtils;
import org.apache.commons.collections.list.LazyList;
import matrix.nimble.edp.cutoff.model.CutOffRecord;
import matrix.nimble.utilities.CommonFunctions;
import matrix.nimble.utilities.DBFunctions;
import matrix.nimble.utilities.GlobalClass;
@@ -21,8 +14,6 @@ public class PunchingHandler {
private String dynamicpanel;
private String dynamicsection;
private String dynamicfields;
private String docdynamicfields;
private String docdynamicpanel;
private String portfolioid;
private String [][] optionvals;
@@ -62,18 +53,6 @@ public class PunchingHandler {
public void setDynamicpanel(String dynamicpanel) {
this.dynamicpanel = dynamicpanel;
}
public String getDocdynamicfields() {
return docdynamicfields;
}
public void setDocdynamicfields(String docdynamicfields) {
this.docdynamicfields = docdynamicfields;
}
public String getDocdynamicpanel() {
return docdynamicpanel;
}
public void setDocdynamicpanel(String docdynamicpanel) {
this.docdynamicpanel = docdynamicpanel;
}
public String getDynamicsection() {
return dynamicsection;
}
@@ -119,70 +98,6 @@ public class PunchingHandler {
setOptionvals(null);
}
}
public void DocDynamicHtml()
{
DBFunctions dbf=new DBFunctions(getErrCode());
dbf.setProcessFlag(true);
setDynamicfields("");
setDynamicpanel("");
setDocdynamicfields("");
setDocdynamicpanel("");
dbf.FetchRunQuery(74, (getPortfolioid()+GlobalClass.ColDelim+"75"+GlobalClass.ColDelim+"ADDDOC"+GlobalClass.ColDelim).split(GlobalClass.ColDelim));
if(dbf.isProcessFlag())
{
CommonFunctions Cfunc=new CommonFunctions();
String [][] ResultSet=dbf.getResultArray();
if(ResultSet.length > 0)
{
Cfunc.setGeneratedHtml("");
Cfunc.setPrevControl("");
Cfunc.setDynamicCtrls("");
for(int indx=0;indx<ResultSet.length;indx++)
{
String ControlVal="";
String secContainer="";
String Temp="";
secContainer=Cfunc.DynamicControls(ResultSet[indx], ControlVal);
if(secContainer.equals("Generalsec"))
{
Temp=getDynamicpanel();
setDynamicfields(getDynamicfields()+ResultSet[indx][2]+GlobalClass.ColDelim);
if(Temp.endsWith("</select></div></div></div>") && Cfunc.getGeneratedHtml().endsWith("</select></div></div></div>"))
{
if(!Cfunc.getGeneratedHtml().startsWith("<div class='widget'>"))
{
Temp=Temp.substring(0,Temp.lastIndexOf("</select></div></div></div>"));
}
}
setDynamicpanel(Temp+""+Cfunc.getGeneratedHtml());
}
if(secContainer.equals("Docsec"))
{
Temp=getDocdynamicpanel();
setDocdynamicfields(getDocdynamicfields()+ResultSet[indx][2]+GlobalClass.ColDelim);
if(Temp.endsWith("</select></div></div></div>") && Cfunc.getGeneratedHtml().endsWith("</select></div></div></div>"))
{
if(!Cfunc.getGeneratedHtml().startsWith("<div class='widget'>"))
{
Temp=Temp.substring(0,Temp.lastIndexOf("</select></div></div></div>"));
}
}
setDocdynamicpanel(Temp+""+Cfunc.getGeneratedHtml());
}
}
}
else
{
setProcessFlag(false);
setErrMsg(dbf.getErrMsg());
setErrDesc(dbf.getErrDesc());
}
}
}
public void DynamicHtml(String pageId)
{
DBFunctions dbf=new DBFunctions(getErrCode());
@@ -242,11 +157,6 @@ public class PunchingHandler {
setErrDesc(dbf.getErrDesc());
}
}
public void AddEditDocs(String docType,String docHolder,String serviceProvider,String uniqueNo,String bankId,String yearMonth,String city,String vendorId,String uuId,String userId)
{
}
public String[][] loadCasesForAddrCorrection() {
String [][]resultArray = null;
DBFunctions dbf=new DBFunctions(getErrCode());

View File

@@ -0,0 +1,23 @@
package matrix.nimble.query;
import com.cygnus.db.QueryDefinition;
import com.cygnus.db.QueryDefinitionProvider;
public final class CloudQueryDefinitionProvider implements QueryDefinitionProvider {
private final QueryProvider provider;
public CloudQueryDefinitionProvider(QueryProvider provider) {
this.provider = provider;
}
@Override
public QueryDefinition get(int queryId) {
return QueryDefinition.parse(queryId, provider.getQuery(queryId));
}
@Override
public QueryDefinition get(String queryKey) {
int diagnosticId = Math.max(1, queryKey.hashCode() & Integer.MAX_VALUE);
return QueryDefinition.parse(diagnosticId, provider.getQuery(queryKey));
}
}

View File

@@ -19,4 +19,11 @@ public final class CloudQuerySource implements QuerySource {
.orElseThrow(() -> new QueryProviderException(
"Cloud query was empty: " + queryId));
}
@Override
public String fetch(String queryKey) {
return client.fetchQuery(queryKey).map(response -> response.query()).blockOptional()
.filter(query -> !query.isBlank())
.orElseThrow(() -> new QueryProviderException("Cloud query was empty: " + queryKey));
}
}

View File

@@ -0,0 +1,21 @@
package matrix.nimble.query;
import java.util.Objects;
public final class DirectQueryProvider implements QueryProvider {
private final QuerySource source;
public DirectQueryProvider(QuerySource source) {
this.source = Objects.requireNonNull(source, "source");
}
@Override
public String getQuery(int queryId) {
return source.fetch(queryId);
}
@Override
public String getQuery(String queryKey) {
return source.fetch(queryKey);
}
}

View File

@@ -0,0 +1,34 @@
package matrix.nimble.query;
import com.cygnus.db.CygnusDbExecutor;
import com.cygnus.db.ExecutorOptions;
import com.cygnus.db.JdbcCygnusDbExecutor;
import matrix.nimble.utilities.DatabaseConnectionPool;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ModernDbConfiguration implements DisposableBean {
private CygnusDbExecutor installed;
@Bean
CygnusDbExecutor cygnusDbExecutor(
QueryProvider queryProvider,
@Value("${CYGNUS_DB_FETCH_SIZE:250}") int fetchSize,
@Value("${CYGNUS_DB_QUERY_TIMEOUT_SECONDS:60}") int queryTimeoutSeconds) {
installed = new JdbcCygnusDbExecutor(
DatabaseConnectionPool.dataSource(),
new CloudQueryDefinitionProvider(queryProvider),
new ExecutorOptions(fetchSize, queryTimeoutSeconds));
ModernDbExecutors.install(installed);
return installed;
}
@Override
public void destroy() {
if (installed != null)
ModernDbExecutors.clear(installed);
}
}

View File

@@ -0,0 +1,24 @@
package matrix.nimble.query;
import com.cygnus.db.CygnusDbExecutor;
import java.util.concurrent.atomic.AtomicReference;
public final class ModernDbExecutors {
private static final AtomicReference<CygnusDbExecutor> CURRENT = new AtomicReference<>();
private ModernDbExecutors() {}
public static void install(CygnusDbExecutor executor) {
CURRENT.set(java.util.Objects.requireNonNull(executor, "executor"));
}
public static CygnusDbExecutor current() {
CygnusDbExecutor executor = CURRENT.get();
if (executor == null) throw new IllegalStateException("Modern database executor is not initialized");
return executor;
}
public static void clear(CygnusDbExecutor executor) {
CURRENT.compareAndSet(executor, null);
}
}

View File

@@ -1,6 +1,10 @@
package matrix.nimble.query;
@FunctionalInterface
public interface QueryProvider {
String getQuery(int queryId);
default String getQuery(String queryKey) {
throw new UnsupportedOperationException("Query keys are not supported by this provider");
}
}

View File

@@ -23,12 +23,14 @@ public class QueryProviderConfiguration implements DisposableBean {
OnPremRedisCacheService cache,
CloudIdentityClient cloudClient,
CloudClientProperties cloudProperties,
@Value("${CYGNUS_QUERY_CACHE_ENABLED:true}") boolean cacheEnabled,
@Value("${CYGNUS_QUERY_CACHE_AES_KEY:}") String configuredKey) {
byte[] key = queryCacheKey(configuredKey, cloudProperties.clientAssertion());
installed = new RedisCachingQueryProvider(
cache,
new CloudQuerySource(cloudClient),
new AesGcmQueryCipher(key));
QuerySource cloudSource = new CloudQuerySource(cloudClient);
installed = cacheEnabled
? new RedisCachingQueryProvider(
cache, cloudSource, new AesGcmQueryCipher(
queryCacheKey(configuredKey, cloudProperties.clientAssertion())))
: new DirectQueryProvider(cloudSource);
QueryProviders.install(installed);
return installed;
}

View File

@@ -4,4 +4,7 @@ package matrix.nimble.query;
public interface QuerySource {
String fetch(int queryId);
default String fetch(String queryKey) {
throw new UnsupportedOperationException("Query keys are not supported by this source");
}
}

View File

@@ -7,7 +7,7 @@ import java.util.logging.Logger;
public final class RedisCachingQueryProvider implements QueryProvider {
public static final Duration QUERY_TTL = Duration.ofHours(12);
public static final Duration QUERY_TTL = Duration.ofHours(3);
private static final Logger LOGGER = Logger.getLogger(RedisCachingQueryProvider.class.getName());
private static final int LOCK_COUNT = 64;
@@ -30,7 +30,18 @@ public final class RedisCachingQueryProvider implements QueryProvider {
@Override
public String getQuery(int queryId) {
String cacheKey = cacheKey(queryId);
return get("id:" + cacheKey(queryId), () -> cloudSource.fetch(queryId));
}
@Override
public String getQuery(String queryKey) {
if (queryKey == null || !queryKey.matches("[A-Z][A-Z0-9_]{2,99}")) {
throw new IllegalArgumentException("Invalid query key");
}
return get("key:" + queryKey, () -> cloudSource.fetch(queryKey));
}
private String get(String cacheKey, java.util.function.Supplier<String> source) {
Optional<String> cached = cached(cacheKey);
if (cached.isPresent()) {
return cached.get();
@@ -42,14 +53,14 @@ public final class RedisCachingQueryProvider implements QueryProvider {
return cached.get();
}
try {
String query = cloudSource.fetch(queryId);
String query = source.get();
cache.put(cacheKey, cipher.encrypt(cacheKey, query), QUERY_TTL);
return query;
} catch (QueryProviderException exception) {
throw exception;
} catch (RuntimeException exception) {
throw new QueryProviderException(
"Unable to retrieve query: " + queryId, exception);
"Unable to retrieve query: " + cacheKey, exception);
}
}
}

View File

@@ -0,0 +1,174 @@
package matrix.nimble.security;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.security.spec.MGF1ParameterSpec;
import java.time.Duration;
import java.time.Instant;
import java.time.format.DateTimeParseException;
import java.util.Base64;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.OAEPParameterSpec;
import javax.crypto.spec.PSource;
import javax.crypto.spec.SecretKeySpec;
import lib.constants.ApplicationMessage;
import lib.exceptions.ApplicationException;
import lib.models.CaseSaveRequest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
/** Thread-safe decryption for short-lived form envelopes created with Web Crypto. */
@Service
public final class PayloadCryptoService {
private static final Duration REQUEST_TTL = Duration.ofMinutes(5);
private static final int GCM_TAG_BITS = 128;
private final ObjectMapper objectMapper;
private final PrivateKey privateKey;
private final PublicKey publicKey;
private final String keyId;
private final Map<String, Instant> acceptedRequests = new ConcurrentHashMap<>();
public PayloadCryptoService(
ObjectMapper objectMapper,
@Value("${CYGNUS_PAYLOAD_PRIVATE_KEY:${CYGNUS_CASE_SAVE_PRIVATE_KEY:}}") String privateKeyLocation,
@Value("${CYGNUS_PAYLOAD_PUBLIC_KEY:${CYGNUS_CASE_SAVE_PUBLIC_KEY:}}") String publicKeyLocation) {
this.objectMapper = objectMapper;
KeyPair pair = loadOrGenerate(privateKeyLocation, publicKeyLocation);
this.privateKey = pair.getPrivate();
this.publicKey = pair.getPublic();
this.keyId = fingerprint(publicKey);
}
public String keyId() { return keyId; }
public String encodedPublicKey() {
return Base64.getUrlEncoder().withoutPadding().encodeToString(publicKey.getEncoded());
}
public <T> T decrypt(CaseSaveRequest request, Class<T> payloadType) {
validateEnvelope(request);
Instant now = Instant.now();
Instant submittedAt;
try {
submittedAt = Instant.parse(request.timestamp());
} catch (DateTimeParseException exception) {
throw invalid("Invalid request timestamp", exception);
}
if (submittedAt.isBefore(now.minus(REQUEST_TTL))
|| submittedAt.isAfter(now.plusSeconds(30))) {
throw invalid("Expired request payload");
}
discardExpired(now);
if (acceptedRequests.putIfAbsent(request.requestId(), now) != null) {
throw invalid("Duplicate request payload");
}
try {
Base64.Decoder decoder = Base64.getUrlDecoder();
Cipher keyCipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
keyCipher.init(Cipher.DECRYPT_MODE, privateKey,
new OAEPParameterSpec("SHA-256", "MGF1",
MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT));
byte[] aesKey = keyCipher.doFinal(decoder.decode(request.encryptedKey()));
byte[] iv = decoder.decode(request.initializationVector());
if (iv.length != 12) throw invalid("Invalid initialization vector");
Cipher payloadCipher = Cipher.getInstance("AES/GCM/NoPadding");
payloadCipher.init(Cipher.DECRYPT_MODE,
new SecretKeySpec(aesKey, "AES"), new GCMParameterSpec(GCM_TAG_BITS, iv));
payloadCipher.updateAAD(aad(request));
byte[] json = payloadCipher.doFinal(decoder.decode(request.encryptedPayload()));
return objectMapper.readValue(json, payloadType);
} catch (ApplicationException exception) {
throw exception;
} catch (Exception exception) {
acceptedRequests.remove(request.requestId());
throw invalid("Unable to decrypt payload", exception);
}
}
private byte[] aad(CaseSaveRequest request) {
return String.join("|", request.keyId(), request.requestId(), request.timestamp())
.getBytes(StandardCharsets.UTF_8);
}
private void validateEnvelope(CaseSaveRequest request) {
if (request == null || blank(request.keyId()) || blank(request.encryptedKey())
|| blank(request.initializationVector()) || blank(request.encryptedPayload())
|| blank(request.requestId()) || blank(request.timestamp())) {
throw invalid("Incomplete encrypted request");
}
if (!keyId.equals(request.keyId())) throw invalid("Unsupported encryption key");
}
private void discardExpired(Instant now) {
Instant cutoff = now.minus(REQUEST_TTL);
acceptedRequests.entrySet().removeIf(entry -> entry.getValue().isBefore(cutoff));
}
private KeyPair loadOrGenerate(String privateLocation, String publicLocation) {
if (blank(privateLocation) && blank(publicLocation)) {
try {
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(3072);
return generator.generateKeyPair();
} catch (Exception exception) {
throw new IllegalStateException("Unable to generate payload key pair", exception);
}
}
if (blank(privateLocation) || blank(publicLocation)) {
throw new IllegalStateException(
"Both CYGNUS_PAYLOAD_PRIVATE_KEY and CYGNUS_PAYLOAD_PUBLIC_KEY are required");
}
try {
KeyFactory factory = KeyFactory.getInstance("RSA");
return new KeyPair(
factory.generatePublic(new X509EncodedKeySpec(pem(publicLocation, "PUBLIC KEY"))),
factory.generatePrivate(new PKCS8EncodedKeySpec(pem(privateLocation, "PRIVATE KEY"))));
} catch (Exception exception) {
throw new IllegalStateException("Unable to load payload key pair", exception);
}
}
private byte[] pem(String location, String type) throws Exception {
String path = location.startsWith("file:") ? location.substring(5) : location;
String value = Files.readString(Path.of(path), StandardCharsets.US_ASCII)
.replace("-----BEGIN " + type + "-----", "")
.replace("-----END " + type + "-----", "")
.replaceAll("\\s", "");
return Base64.getDecoder().decode(value);
}
private String fingerprint(PublicKey key) {
try {
byte[] digest = MessageDigest.getInstance("SHA-256").digest(key.getEncoded());
return Base64.getUrlEncoder().withoutPadding().encodeToString(digest);
} catch (Exception exception) {
throw new IllegalStateException("Unable to identify payload key", exception);
}
}
private boolean blank(String value) { return value == null || value.isBlank(); }
private ApplicationException invalid(String technicalMessage) {
return new ApplicationException(ApplicationMessage.PAYLOAD_INVALID, technicalMessage);
}
private ApplicationException invalid(String technicalMessage, Throwable cause) {
return new ApplicationException(ApplicationMessage.PAYLOAD_INVALID, technicalMessage, cause);
}
}

View File

@@ -0,0 +1,16 @@
package matrix.nimble.security;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class WebJsonConfiguration {
@Bean
ObjectMapper webObjectMapper() {
return new ObjectMapper()
.findAndRegisterModules()
.enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
}
}

View File

@@ -7,8 +7,12 @@ import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class CommonFunctions {
private static final Pattern DYNAMIC_VALIDATION = Pattern.compile(
"(?i)validate\\s*\\(\\s*this\\s*,\\s*'([tf])'\\s*,\\s*'([^']*)");
private String ErrMsg;
private String ErrCode;
private String ErrDesc;
@@ -110,6 +114,7 @@ public class CommonFunctions {
String CtrlEvents="";
String isSelected="";
String maxLength="maxlength";
String validationAttributes=dynamicValidationAttributes(Controls[9]);
String unit="px";
setCtrlType(Controls[14]);
ControlVal=(ControlVal==null || ControlVal.equals("")) ? Controls[17] : ControlVal;
@@ -151,11 +156,11 @@ public class CommonFunctions {
CtrlHtml=CtrlHtml+"</div><div class='inputcontainer'>";
if(getCtrlType().equals("text"))
{
CtrlHtml=CtrlHtml+"<input type=\"text\" id='"+Controls[2]+"' name='"+Controls[2]+"' "+maxLength+" "+CtrlEvents+" "+CtrlStyle+" "+CtrlClass+" value=\""+ControlVal+"\" />";
CtrlHtml=CtrlHtml+"<input type=\"text\" id='"+Controls[2]+"' name='"+Controls[2]+"' "+maxLength+" "+validationAttributes+" "+CtrlEvents+" "+CtrlStyle+" "+CtrlClass+" value=\""+ControlVal+"\" />";
}
else if(getCtrlType().equals("checkbox"))
{
CtrlHtml=CtrlHtml+"<input id='"+Controls[2]+"' name='"+Controls[2]+"' "+maxLength+" "+CtrlEvents+" "+CtrlStyle+" "+CtrlClass+" value='"+ControlVal+"' />";
CtrlHtml=CtrlHtml+"<input id='"+Controls[2]+"' name='"+Controls[2]+"' "+maxLength+" "+validationAttributes+" "+CtrlEvents+" "+CtrlStyle+" "+CtrlClass+" value='"+ControlVal+"' />";
}
CtrlHtml=CtrlHtml+"</div></div>";
}
@@ -167,7 +172,7 @@ public class CommonFunctions {
}
CtrlHtml="<div class='widget'><div class='lblcontainer'>"+Controls[1];
CtrlHtml=CtrlHtml+"</div><div class='inputcontainer'>";
CtrlHtml=CtrlHtml+"<textarea id='"+Controls[2]+"' name='"+Controls[2]+"' "+maxLength+" "+CtrlEvents+" "+CtrlStyle+" "+CtrlClass+" >"+ControlVal+"</textarea>";
CtrlHtml=CtrlHtml+"<textarea id='"+Controls[2]+"' name='"+Controls[2]+"' "+maxLength+" "+validationAttributes+" "+CtrlEvents+" "+CtrlStyle+" "+CtrlClass+" >"+ControlVal+"</textarea>";
CtrlHtml=CtrlHtml+"</div></div>";
}
else if(getCtrlType().equals("select"))
@@ -194,7 +199,7 @@ public class CommonFunctions {
CtrlHtml="<div class='widget'><div class='lblcontainer'>"+Controls[1];
CtrlHtml=CtrlHtml+"</div><div class='inputcontainer'>";
CtrlHtml=CtrlHtml+"<div "+CtrlClass+" id='div"+Controls[2]+"' "+CtrlStyle+" >";
CtrlHtml=CtrlHtml+"<select id='"+Controls[2]+"' name='"+Controls[2]+"' "+CtrlEvents+" "+CtrlStyle1+" >";
CtrlHtml=CtrlHtml+"<select id='"+Controls[2]+"' name='"+Controls[2]+"' "+validationAttributes+" "+CtrlEvents+" "+CtrlStyle1+" >";
CtrlHtml=CtrlHtml+"<option value='-1' selected>NA</option>";
CtrlHtml=CtrlHtml+"<option value='"+Controls[19]+"' "+isSelected+" >"+Controls[19]+"</option></select></div></div></div>";
}
@@ -213,6 +218,16 @@ public class CommonFunctions {
}
return Controls[4];
}
private String dynamicValidationAttributes(String onBlur)
{
if(onBlur==null || onBlur.isBlank()) return "";
Matcher matcher=DYNAMIC_VALIDATION.matcher(onBlur);
if(!matcher.find()) return "";
String format=matcher.group(2).trim().replaceFirst("[^A-Za-z0-9]+$", "");
return "data-validation-required='"+(matcher.group(1).equalsIgnoreCase("t") ? "true" : "false")+
"' data-validation-format='"+format+"'";
}
public String DesignControls(String ControlType,String Controlid,String TypeScript,String ValidationScript,String Style, String CssClass,String Fieldid,DBFunctions DBFunc,StringFunctions SFunc,String ControlVal)
{
String HtmlControl="";

View File

@@ -1,6 +1,14 @@
package matrix.nimble.utilities;
import java.sql.*;
import java.util.Hashtable;
import java.util.List;
import java.util.Optional;
import com.cygnus.db.DbResult;
import com.cygnus.db.RowMapper;
import com.cygnus.db.RowView;
import com.cygnus.db.RowConsumer;
import com.cygnus.db.TransactionCallback;
import matrix.nimble.query.ModernDbExecutors;
public class DBFunctions {
private Connection con;
@@ -368,6 +376,59 @@ public class DBFunctions {
return getErrMsg();
}
}
public DbResult<RowView> execute(int queryId, Object[] parameters) {
return ModernDbExecutors.current().execute(queryId, parameters);
}
public <T> DbResult<T> execute(int queryId, Object[] parameters, Class<T> responseType) {
return ModernDbExecutors.current().execute(queryId, parameters, responseType);
}
public <T> List<T> query(int queryId, Object[] parameters, Class<T> responseType) {
return ModernDbExecutors.current().query(queryId, parameters, responseType);
}
public <T> List<T> query(int queryId, Object[] parameters, RowMapper<T> mapper) {
return ModernDbExecutors.current().query(queryId, parameters, mapper);
}
public <T> Optional<T> queryOne(int queryId, Object[] parameters, Class<T> responseType) {
return ModernDbExecutors.current().queryOne(queryId, parameters, responseType);
}
public int insert(int queryId, Object[] parameters) {
return ModernDbExecutors.current().insert(queryId, parameters);
}
public <K> K insert(int queryId, Object[] parameters, Class<K> generatedKeyType) {
return ModernDbExecutors.current().insert(queryId, parameters, generatedKeyType);
}
public int update(int queryId, Object[] parameters) {
return ModernDbExecutors.current().update(queryId, parameters);
}
public int delete(int queryId, Object[] parameters) {
return ModernDbExecutors.current().delete(queryId, parameters);
}
public <T> T procedure(int queryId, Object[] parameters, Class<T> responseType) {
return ModernDbExecutors.current().procedure(queryId, parameters, responseType);
}
public <T> List<T> procedureRows(int queryId, Object[] parameters, Class<T> responseType) {
return ModernDbExecutors.current().procedureRows(queryId, parameters, responseType);
}
public <T> void stream(
int queryId, Object[] parameters, RowMapper<T> mapper, RowConsumer<T> consumer) {
ModernDbExecutors.current().stream(queryId, parameters, mapper, consumer);
}
public <T> T transaction(TransactionCallback<T> callback) {
return ModernDbExecutors.current().transaction(callback);
}
@SuppressWarnings("finally")
public String QueryBuilder(String Query,String[] Val)
{

View File

@@ -5,6 +5,7 @@ import java.sql.SQLException;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import javax.sql.DataSource;
/** Shared, bounded JDBC connection pool for the legacy database layer. */
public final class DatabaseConnectionPool {
@@ -20,6 +21,10 @@ public final class DatabaseConnectionPool {
return getDataSource().getConnection();
}
public static DataSource dataSource() {
return getDataSource();
}
private static HikariDataSource getDataSource() {
HikariDataSource current = dataSource;
if (current != null) {

View File

@@ -0,0 +1,33 @@
package matrix.services.commons;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lib.models.MessageDetails;
import matrix.nimble.model.Session;
import org.springframework.stereotype.Service;
import org.springframework.ui.ModelMap;
@Service
public class CommonErrorService {
public static final String ERROR_ATTRIBUTE = "messageDetails";
private final CommonService commonService;
public CommonErrorService(CommonService commonService) {
this.commonService = commonService;
}
public String render(
ModelMap model,
HttpServletResponse response,
HttpSession httpSession,
MessageDetails messageDetails) {
response.setStatus(messageDetails.getHttpStatus());
model.addAttribute(ERROR_ATTRIBUTE, messageDetails);
Session session = commonService.getSession(httpSession);
if (session != null) {
model.addAttribute(CommonService.SESSION_ATTRIBUTE, session);
}
return "error";
}
}

View File

@@ -0,0 +1,141 @@
package matrix.services.commons;
import com.cygnus.db.CygnusDbExecutor;
import jakarta.servlet.http.HttpSession;
import lib.models.Option;
import lib.models.UserSession;
import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import matrix.nimble.model.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class CommonService {
public static final String SESSION_ATTRIBUTE = "Sessvals";
public static final String USER_SESSION_ATTRIBUTE = "userSession";
private static final Pattern MENU_COMMAND = Pattern.compile(
"SubmitMenuCommand\\(\\s*'([^']+)'\\s*,",
Pattern.CASE_INSENSITIVE);
private final CygnusDbExecutor dbExecutor;
@Autowired
public CommonService(CygnusDbExecutor dbExecutor) {
this.dbExecutor = Objects.requireNonNull(dbExecutor, "dbExecutor");
}
/* Used by the session-only unit tests. Production construction is handled
by Spring through the CygnusDbExecutor constructor above. */
public CommonService() {
this.dbExecutor = null;
}
public Session getSession(HttpSession httpSession) {
if (httpSession == null) {
return null;
}
Object value = httpSession.getAttribute(SESSION_ATTRIBUTE);
return value instanceof Session session ? session : null;
}
public void storeSession(HttpSession httpSession, Session session) {
Objects.requireNonNull(httpSession, "httpSession");
httpSession.setAttribute(SESSION_ATTRIBUTE, Objects.requireNonNull(session, "session"));
}
public UserSession getUserSession(HttpSession httpSession) {
if (httpSession == null) {
return null;
}
Object value = httpSession.getAttribute(USER_SESSION_ATTRIBUTE);
return value instanceof UserSession session ? session : null;
}
public void storeUserSession(HttpSession httpSession, UserSession session) {
Objects.requireNonNull(httpSession, "httpSession");
httpSession.setAttribute(
USER_SESSION_ATTRIBUTE, Objects.requireNonNull(session, "session"));
}
public boolean hasPageAccess(HttpSession httpSession, String pageRoute) {
return hasPageAccess(getSession(httpSession), pageRoute);
}
public boolean hasPageAccess(Session session, String pageRoute) {
if (session == null || session.getMenuHtml() == null) {
return false;
}
String requiredRoute = normalizeRoute(pageRoute);
if (requiredRoute.isEmpty()) {
return false;
}
Matcher matcher = MENU_COMMAND.matcher(session.getMenuHtml());
while (matcher.find()) {
if (normalizeRoute(matcher.group(1)).equals(requiredRoute)) {
return true;
}
}
return false;
}
public boolean hasPageAccess(UserSession session, String pageRoute) {
return session != null && hasPageAccess(session.getMenuHtml(), pageRoute);
}
private boolean hasPageAccess(String menuHtml, String pageRoute) {
if (menuHtml == null) {
return false;
}
String requiredRoute = normalizeRoute(pageRoute);
if (requiredRoute.isEmpty()) {
return false;
}
Matcher matcher = MENU_COMMAND.matcher(menuHtml);
while (matcher.find()) {
if (normalizeRoute(matcher.group(1)).equals(requiredRoute)) {
return true;
}
}
return false;
}
private String normalizeRoute(String route) {
if (route == null) {
return "";
}
String normalized = route.trim().replace('\\', '/');
int query = normalized.indexOf('?');
if (query >= 0) {
normalized = normalized.substring(0, query);
}
int fragment = normalized.indexOf('#');
if (fragment >= 0) {
normalized = normalized.substring(0, fragment);
}
while (normalized.endsWith("/")) {
normalized = normalized.substring(0, normalized.length() - 1);
}
int slash = normalized.lastIndexOf('/');
return slash >= 0 ? normalized.substring(slash + 1) : normalized;
}
public List<Option> getOptions(Integer queryId, Object[] queryParams) {
if (queryId == null) {
return List.of();
}
if (dbExecutor == null) {
throw new IllegalStateException("CygnusDbExecutor is not configured");
}
Object[] parameters = queryParams == null ? new Object[0] : queryParams;
return dbExecutor.query(queryId, parameters, Option.class);
}
}

View File

@@ -0,0 +1,503 @@
package matrix.services.edp;
import com.cygnus.db.CygnusDbExecutor;
import com.cygnus.db.RowView;
import com.cygnus.db.SqlArrayParameter;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import java.sql.SQLException;
import java.sql.Date;
import java.time.LocalDate;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import lib.models.ApplicationDetails;
import lib.models.CasePunching;
import lib.models.ApplicationSaveResult;
import lib.models.MessageDetails;
import lib.models.Option;
import lib.models.PunchedRecordsData;
import lib.models.DuplicateDetailsData;
import lib.models.EditCaseSummary;
import lib.models.LocalityData;
import lib.models.LocalityOption;
import lib.models.UserSession;
import lib.constants.ApplicationMessage;
import lib.exceptions.ApplicationException;
import matrix.nimble.edp.punching.model.PunchingHandler;
import matrix.nimble.utilities.GlobalClass;
import matrix.services.commons.CommonService;
@Service
public class PunchingService {
private static final String PORTFOLIO = "portfolio.";
private static final String BRANCH = "branch.";
private static final String PRODUCT = "product.";
private static final String CITY = "city.";
private static final String APPLICATION_TYPE = "applicationType.";
private static final String DATABASE_APPLICATION_TYPE = "apptype.";
private static final String CATEGORY = "category.";
private static final Short ACTIVE = Short.valueOf((short) 1);
private static final int PUNCHED_RECORDS_QUERY = 24;
private static final int EDIT_CASES_QUERY = 23;
private static final int EDIT_CASE_PORTFOLIOS_QUERY = 249;
private static final int LOCALITY_QUERY = 13;
private static final int RESIDENCE_DETAILS_QUERY = 19;
private static final int OFFICE_DETAILS_QUERY = 20;
private static final int PROPERTY_DETAILS_QUERY = 21;
private static final int CO_APPLICANT_DETAILS_QUERY = 22;
private static final Pattern DYNAMIC_FIELD = Pattern.compile(
"(?:field(?:[1-9]|1[0-2]|150(?:_2)?)|dtfield1)", Pattern.CASE_INSENSITIVE);
private static final SqlArrayParameter GENERAL_OPTION_TYPES =
SqlArrayParameter.text("CITY", "APPTYPE");
private static final SqlArrayParameter PORTFOLIO_OPTION_TYPES =
SqlArrayParameter.text("CATEGORY", "PRODUCT");
private final CommonService commonService;
private final CygnusDbExecutor dbExecutor;
private final ObjectMapper objectMapper;
public PunchingService(CommonService commonService) {
this.commonService = commonService;
this.dbExecutor = null;
this.objectMapper = null;
}
@Autowired
public PunchingService(
CommonService commonService, CygnusDbExecutor dbExecutor, ObjectMapper objectMapper) {
this.commonService = commonService;
this.dbExecutor = dbExecutor;
this.objectMapper = objectMapper;
}
public ApplicationSaveResult saveApplication(ApplicationDetails details, UserSession session) {
if (dbExecutor == null || objectMapper == null) {
throw new IllegalStateException("Application-save dependencies are not configured");
}
validate(details, session);
sanitizeDynamicFields(details);
try {
String json = objectMapper.writeValueAsString(details);
ApplicationSaveResult result = dbExecutor.procedure("APPLICATION_SAVE",
new Object[] {json, session.getCompanyId(), session.getBranchId(),
session.getUserId()}, ApplicationSaveResult.class);
if (result == null || result.getApplicationId() == null) {
throw new ApplicationException(
ApplicationMessage.APPLICATION_SAVE_FAILED, "Database returned no application result");
}
return result;
} catch (JsonProcessingException exception) {
throw new ApplicationException(
ApplicationMessage.PAYLOAD_INVALID, "Unable to serialize application details", exception);
} catch (ApplicationException exception) {
throw exception;
} catch (RuntimeException exception) {
throw databaseFailure(exception);
}
}
public List<Option> loadEditCasePortfolios(UserSession session) {
requireSessionScope(session);
return commonService.getOptions(EDIT_CASE_PORTFOLIOS_QUERY, new Object[] {
session.getCompanyId(), session.getBranchId(), session.getUserId(),
session.getUserId(), ACTIVE
});
}
public List<EditCaseSummary> loadEditableCases(Short portfolioId, UserSession session) {
requireSessionScope(session);
if (portfolioId == null || portfolioId <= 0) {
throw new ApplicationException(
ApplicationMessage.APPLICATION_VALIDATION_FAILED, "Portfolio is required");
}
try {
return dbExecutor.query(EDIT_CASES_QUERY, new Object[] {
portfolioId, session.getCompanyId(), session.getBranchId()
}, EditCaseSummary.class);
} catch (RuntimeException exception) {
throw databaseFailure(exception);
}
}
private void requireSessionScope(UserSession session) {
if (session == null || session.getCompanyId() == null || session.getBranchId() == null
|| session.getUserId() == null) {
throw new ApplicationException(
ApplicationMessage.SESSION_REQUIRED, "Authenticated session scope is required");
}
if (dbExecutor == null) {
throw new IllegalStateException("Database dependencies are not configured");
}
}
public PunchedRecordsData loadPunchedRecords(
Short portfolioId, String documentCaseId, UserSession session) {
if (dbExecutor == null || objectMapper == null) {
throw new IllegalStateException("Punched-record dependencies are not configured");
}
if (portfolioId == null || portfolioId <= 0 || session == null) {
throw new ApplicationException(
ApplicationMessage.APPLICATION_VALIDATION_FAILED, "Portfolio is required");
}
String caseUuid = documentCaseId != null && documentCaseId.trim().length() > 20
? documentCaseId.trim() : "";
try {
List<RowView> rows = dbExecutor.query(PUNCHED_RECORDS_QUERY, new Object[] {
caseUuid, caseUuid, caseUuid, portfolioId,
session.getCompanyId(), session.getBranchId()
});
return new PunchedRecordsData(rows.stream().map(this::toPunchedRecord).toList());
} catch (ApplicationException exception) {
throw exception;
} catch (RuntimeException exception) {
throw databaseReadFailure(exception);
}
}
public DuplicateDetailsData findDuplicateDetails(
String applicationNumber, Short portfolioId, Integer queryId, UserSession session) {
if (dbExecutor == null) {
throw new IllegalStateException("Duplicate-detail dependencies are not configured");
}
if (blank(applicationNumber) || portfolioId == null || portfolioId <= 0
|| queryId == null || session == null) {
throw new ApplicationException(
ApplicationMessage.APPLICATION_VALIDATION_FAILED, "Duplicate search details are invalid");
}
Date receivedDate = Date.valueOf(LocalDate.now());
Object[] parameters = switch (queryId) {
case RESIDENCE_DETAILS_QUERY, OFFICE_DETAILS_QUERY, CO_APPLICANT_DETAILS_QUERY ->
new Object[] {applicationNumber.trim(), portfolioId, receivedDate,
session.getCompanyId(), session.getBranchId()};
case PROPERTY_DETAILS_QUERY ->
new Object[] {applicationNumber.trim(), portfolioId,
session.getCompanyId(), session.getBranchId(), receivedDate};
default -> throw new ApplicationException(
ApplicationMessage.APPLICATION_VALIDATION_FAILED, "Unsupported duplicate search type");
};
try {
List<Map<String, Object>> records = dbExecutor.query(queryId, parameters).stream()
.map(row -> {
Map<String, Object> record = new LinkedHashMap<>();
row.asMap().forEach((name, value) -> record.put(name, value == null ? "" : value));
return record;
})
.toList();
return new DuplicateDetailsData(records);
} catch (ApplicationException exception) {
throw exception;
} catch (RuntimeException exception) {
throw databaseFailure(exception);
}
}
public LocalityData findLocalities(String city, String letters, UserSession session) {
if (dbExecutor == null) {
throw new IllegalStateException("Locality dependencies are not configured");
}
String normalizedCity = city == null ? "-1" : city.trim();
String prefix = letters == null ? "" : letters.trim();
if (session == null || session.getBranchId() == null || prefix.isEmpty()
|| prefix.length() > 50 || normalizedCity.length() > 100) {
throw new ApplicationException(
ApplicationMessage.APPLICATION_VALIDATION_FAILED, "Locality search details are invalid");
}
try {
List<LocalityOption> localities = dbExecutor.query(LOCALITY_QUERY, new Object[] {
session.getBranchId(), prefix, normalizedCity, normalizedCity
}).stream().map(row -> new LocalityOption(
row.get("id", Integer.class), rowText(row, "location"),
rowText(row, "pincode").trim(), rowText(row, "city"))).toList();
return new LocalityData(localities);
} catch (ApplicationException exception) {
throw exception;
} catch (RuntimeException exception) {
throw new ApplicationException(
ApplicationMessage.INTERNAL_SERVER_ERROR, "Locality lookup failed", exception);
}
}
private String rowText(RowView row, String column) {
Object value = row.get(column);
return value == null ? "" : value.toString();
}
private Map<String, Object> toPunchedRecord(RowView row) {
Map<String, Object> record = new LinkedHashMap<>();
row.asMap().forEach((name, value) -> {
if (!"dynamic_fields".equalsIgnoreCase(name)) record.put(name, value == null ? "" : value);
});
Object dynamicValue = row.get("dynamic_fields");
if (dynamicValue == null || dynamicValue.toString().isBlank()) return record;
try {
Map<String, Object> dynamicFields = objectMapper.readValue(
dynamicValue.toString(), new TypeReference<Map<String, Object>>() {});
dynamicFields.forEach((name, value) -> {
if (name != null && DYNAMIC_FIELD.matcher(name).matches()) {
record.put(name, value == null ? "" : value);
}
});
return record;
} catch (JsonProcessingException exception) {
throw new ApplicationException(
ApplicationMessage.INTERNAL_SERVER_ERROR,
"Punched-record dynamic fields are invalid", exception);
}
}
private void validate(ApplicationDetails details, UserSession session) {
if (details == null || session == null || details.getPortfolioId() == null
|| details.getPortfolioId() <= 0) {
throw new ApplicationException(
ApplicationMessage.APPLICATION_VALIDATION_FAILED, "Portfolio is required");
}
if (details.getBankBranchId() == null || details.getBankBranchId() <= 0) {
throw new ApplicationException(
ApplicationMessage.APPLICATION_VALIDATION_FAILED, "Bank branch is required");
}
if (blank(details.getApplicationNumber()) || blank(details.getProduct())
|| blank(details.getCustomerName()) || blank(details.getApplicationType())) {
throw new ApplicationException(
ApplicationMessage.APPLICATION_VALIDATION_FAILED, "Required application fields are missing");
}
if (!Boolean.TRUE.equals(details.getResidenceVerification())
&& !Boolean.TRUE.equals(details.getResidenceTelephoneVerification())
&& !Boolean.TRUE.equals(details.getOfficeVerification())
&& !Boolean.TRUE.equals(details.getOfficeTelephoneVerification())
&& !Boolean.TRUE.equals(details.getPropertyVerification())
&& !Boolean.TRUE.equals(details.getReferenceVerification())
&& !Boolean.TRUE.equals(details.getDocumentVerification())) {
throw new ApplicationException(
ApplicationMessage.APPLICATION_VALIDATION_FAILED,
"At least one verification type is required");
}
}
private void sanitizeDynamicFields(ApplicationDetails details) {
if (details.getDynamicFields() == null || details.getDynamicFields().isEmpty()) {
details.setDynamicFields(new LinkedHashMap<>());
return;
}
Map<String, String> allowed = new LinkedHashMap<>();
details.getDynamicFields().forEach((name, value) -> {
if (name != null && DYNAMIC_FIELD.matcher(name).matches()) {
allowed.put(name, value == null ? null : value.trim());
}
});
details.setDynamicFields(allowed);
}
private ApplicationException databaseFailure(RuntimeException exception) {
Throwable cause = exception;
while (cause != null) {
if (cause instanceof SQLException sqlException) {
return switch (sqlException.getSQLState()) {
case "42501" -> new ApplicationException(
ApplicationMessage.APPLICATION_ACCESS_DENIED, sqlException.getMessage(), exception);
case "22023", "23502", "23503" -> new ApplicationException(
ApplicationMessage.APPLICATION_VALIDATION_FAILED, sqlException.getMessage(), exception);
case "23505" -> new ApplicationException(
ApplicationMessage.APPLICATION_SAVE_CONFLICT, sqlException.getMessage(), exception);
default -> new ApplicationException(
ApplicationMessage.APPLICATION_SAVE_FAILED, "Database save failed", exception);
};
}
cause = cause.getCause();
}
return new ApplicationException(
ApplicationMessage.APPLICATION_SAVE_FAILED, "Database save failed", exception);
}
private ApplicationException databaseReadFailure(RuntimeException exception) {
return new ApplicationException(
ApplicationMessage.APPLICATION_LOAD_FAILED,
"Database read failed", exception);
}
private boolean blank(String value) { return value == null || value.isBlank(); }
public CasePunching init(
Short branchId,
Short userId,
String verificationCaseId,
String documentCaseId) {
PunchingHandler punchingHandler = new PunchingHandler();
punchingHandler.setErrCode("1001");
CasePunching casePunching = new CasePunching();
Map<String, List<Option>> options = new LinkedHashMap<>();
List<Option> portfolios = commonService.getOptions(
3, new Object[] { branchId, ACTIVE });
addOptions(options, PORTFOLIO, portfolios);
casePunching.setOptions(freezeOptions(options));
casePunching.setVisibleSections(List.of());
casePunching.setPortfolioId((short) -1);
casePunching.setFormMode(0);
casePunching.setUserId(Short.toString(userId));
casePunching.setDynamicFields("");
casePunching.setDynamicHtml("");
casePunching.setVerificationCaseId(verificationCaseId);
casePunching.setDocumentCaseId(documentCaseId);
return casePunching;
}
public CasePunching prepareNewApplication(
CasePunching submitted,
Short branchId,
Short companyId,
Short userId) {
CasePunching result = new CasePunching();
result.setPortfolioId(submitted.getPortfolioId());
result.setFormMode(1);
result.setUserId(Short.toString(userId));
result.setVerificationCaseId(submitted.getVerificationCaseId());
result.setDocumentCaseId("xxx");
if (submitted.getPortfolioId() == null || submitted.getPortfolioId() <= 0) {
result.setOptions(Map.of());
result.setVisibleSections(List.of());
result.setDynamicFields("");
result.setDynamicHtml("");
result.setMessageDetails(new MessageDetails(ApplicationMessage.BAD_REQUEST));
return result;
}
Short portfolioId = submitted.getPortfolioId();
PunchingHandler punchingHandler = new PunchingHandler();
punchingHandler.setErrCode("1001");
punchingHandler.setPortfolioid(Short.toString(portfolioId));
punchingHandler.setProcessFlag(true);
punchingHandler.DynamicHtml("10");
if (punchingHandler.isProcessFlag()) {
result.setDynamicFields(defaultString(punchingHandler.getDynamicfields()));
result.setDynamicHtml(defaultString(punchingHandler.getDynamicpanel()));
String sections = defaultString(punchingHandler.GetVisibleSections())
+ defaultString(punchingHandler.getDynamicsection());
result.setVisibleSections(toVisibleSections(sections));
} else {
result.setDynamicFields("");
result.setDynamicHtml("");
result.setVisibleSections(List.of());
result.setMessageDetails(new MessageDetails(ApplicationMessage.INTERNAL_SERVER_ERROR));
}
result.setOptions(loadOptions(branchId, companyId, portfolioId));
return result;
}
Map<String, List<Option>> loadOptions(
Short branchId, Short companyId, Short portfolioId) {
Map<String, List<Option>> options = new LinkedHashMap<>();
addOptions(options, PORTFOLIO, commonService.getOptions(
3, new Object[] {branchId, ACTIVE}));
addOptions(options, BRANCH, commonService.getOptions(
4, new Object[] {portfolioId, ACTIVE}));
addGroupedOptions(options, commonService.getOptions(
5, new Object[] {companyId, GENERAL_OPTION_TYPES}));
addGroupedOptions(options, commonService.getOptions(
70, new Object[] {portfolioId, PORTFOLIO_OPTION_TYPES}));
return freezeOptions(options);
}
public CasePunching prepareApplicationEdit(
Short portfolioId,
String documentCaseId,
Short branchId,
Short companyId,
Short userId) {
CasePunching submitted = new CasePunching();
submitted.setPortfolioId(portfolioId);
submitted.setDocumentCaseId(documentCaseId);
CasePunching result = prepareNewApplication(submitted, branchId, companyId, userId);
result.setFormMode(2);
result.setDocumentCaseId(documentCaseId);
return result;
}
private void addOptions(Map<String, List<Option>> options, String prefix, List<Option> values) {
if (values == null || values.isEmpty()) {
return;
}
List<Option> groupOptions = options.get(prefix);
for (Option value : values) {
if (value == null || value.getValue() == null) {
continue;
}
if (groupOptions == null) {
groupOptions = new java.util.ArrayList<>(values.size());
options.put(prefix, groupOptions);
}
groupOptions.add(value);
}
}
private void addGroupedOptions(Map<String, List<Option>> options, List<Option> values) {
if (values == null || values.isEmpty()) {
return;
}
for (Option value : values) {
if (value == null || value.getValue() == null) {
continue;
}
String group = normalizeGroup(value.getGroup());
if (group == null) {
continue;
}
options.computeIfAbsent(group, ignored -> new java.util.ArrayList<>()).add(value);
}
}
private String normalizeGroup(String group) {
if (group == null || group.isBlank()) {
return null;
}
String normalized = group.trim();
if (DATABASE_APPLICATION_TYPE.equalsIgnoreCase(normalized)) {
return APPLICATION_TYPE;
}
if (CITY.equalsIgnoreCase(normalized)) return CITY;
if (CATEGORY.equalsIgnoreCase(normalized)) return CATEGORY;
if (PRODUCT.equalsIgnoreCase(normalized)) return PRODUCT;
return null;
}
private Map<String, List<Option>> freezeOptions(Map<String, List<Option>> options) {
if (options.isEmpty()) {
return Map.of();
}
Map<String, List<Option>> immutable = new LinkedHashMap<>(options.size());
options.forEach((group, values) -> immutable.put(group, List.copyOf(values)));
return Collections.unmodifiableMap(immutable);
}
private List<String> toVisibleSections(String sections) {
if (sections == null || sections.isBlank()) {
return List.of();
}
return List.of(sections.split(Pattern.quote(GlobalClass.ColDelim))).stream()
.map(String::trim)
.filter(section -> !section.isEmpty() && !"null".equalsIgnoreCase(section))
.distinct()
.toList();
}
private String defaultString(String value) {
return value == null ? "" : value;
}
}

View File

@@ -310,7 +310,8 @@ class RoleVisibleBatchMigrationTest {
Path.of("build/WebContent/WEB-INF/app/operation/tools").resolve(page));
assertTrue(content.contains("matrix-shell matrix-tool-workspace"), page);
assertTrue(content.contains("tool-workspace-v3.css"), page);
assertTrue(content.contains("Sessvals.menuHtml"), page);
assertTrue(content.contains("Sessvals.menuHtml")
|| content.contains("sessionScope.userSession.menuHtml"), page);
assertFalse(content.contains("z-index:-1"), page);
assertFalse(content.contains("centerDivBoth(\"formcontainer\""), page);
}
@@ -501,34 +502,22 @@ class RoleVisibleBatchMigrationTest {
assertFalse(documents.contains("z-index:-1"));
Path punching = Path.of("build/WebContent/WEB-INF/app/edp/punching");
for (String page : List.of("addcases.jsp", "initcase.jsp", "initdocs.jsp")) {
for (String page : List.of("initcase.jsp")) {
String content = Files.readString(punching.resolve(page));
assertTrue(content.contains("matrix-tool-workspace matrix-punch-workspace"), page);
assertTrue(content.contains("punch-workspace-v3.css"), page);
assertTrue(content.contains("Sessvals.menuHtml"), page);
assertTrue(content.contains("Sessvals.menuHtml")
|| content.contains("sessionScope.userSession.menuHtml"), page);
assertFalse(content.contains("z-index:-1"), page);
assertFalse(content.contains("centerDivBoth(\"formcontainer\""), page);
}
String addCases = Files.readString(punching.resolve("addcases.jsp"));
assertTrue(addCases.contains("ValidateSubmitForm('caseDetails')"));
assertTrue(addCases.contains("FindSameDet(this,'R','ResiPhone')"));
assertTrue(addCases.contains("matrix-dialog-child.js"));
assertTrue(addCases.contains("MatrixDialog.close(0)"));
assertTrue(addCases.contains("MatrixDialog.close(1)"));
assertFalse(addCases.contains("window.returnValue"));
assertFalse(addCases.contains("window.close()"));
String initialCase = Files.readString(punching.resolve("initcase.jsp"));
assertTrue(initialCase.contains("GotoRecord(this,'recno')"));
assertTrue(initialCase.contains("ValidateSubmitForm('casedetails')"));
assertTrue(initialCase.contains("CygnusInitiation.save(event)"));
assertTrue(initialCase.contains("/matrix/js/edp/punching/initiation.js"));
assertTrue(initialCase.contains("AddNewRecord()"));
String initialDocs = Files.readString(punching.resolve("initdocs.jsp"));
assertTrue(initialDocs.contains("EditBasicDetails()"));
assertTrue(initialDocs.contains("AddDocs()"));
assertTrue(initialDocs.contains("AddNewDoc()"));
String editCases = Files.readString(punching.resolve("editcases.jsp"));
assertTrue(editCases.contains("matrix-tool-workspace"));
assertTrue(editCases.contains("SubmitForm('caselist','_parent','caseGrid')"));
@@ -551,7 +540,7 @@ class RoleVisibleBatchMigrationTest {
assertTrue(workspace.contains("left: auto !important"));
Path punching = Path.of("build/WebContent/WEB-INF/app/edp/punching");
for (String page : List.of("addcases.jsp", "initcase.jsp", "initdocs.jsp")) {
for (String page : List.of("initcase.jsp")) {
String content = Files.readString(punching.resolve(page));
assertTrue(content.contains("matrix-add-cases"), page);
assertTrue(content.contains("add-cases-v4.css"), page);

View File

@@ -5,11 +5,12 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import java.lang.reflect.Method;
import jakarta.servlet.http.HttpSession;
import org.junit.jupiter.api.Test;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.stereotype.Controller;
import matrix.nimble.controller.Ajax;
import matrix.nimble.edp.punching.controllers.PunchingController;
class SpringWebContextTest {
@@ -33,8 +34,8 @@ class SpringWebContextTest {
@Test
void requestParameterNamesAreRetained() throws Exception {
Method method = Ajax.class.getMethod(
"PunchedRecords", String.class, String.class, String.class);
Method method = PunchingController.class.getMethod(
"punchedRecords", Short.class, String.class, HttpSession.class);
assertTrue(method.getParameters()[0].isNamePresent());
assertTrue(method.getParameters()[1].isNamePresent());

View File

@@ -8,13 +8,13 @@ import com.cygnus.client.model.CloudIdentitySession;
import com.cygnus.client.model.CloudMenuItem;
import java.time.Instant;
import java.util.List;
import matrix.nimble.model.Session;
import lib.models.UserSession;
import org.junit.jupiter.api.Test;
class CloudSessionMapperTest {
@Test
void mapsCloudIdentityAndStructuredMenuToLegacySession() {
void mapsCloudIdentityAndStructuredMenuToTypedSession() {
CloudIdentitySession identity = new CloudIdentitySession(
(short) 17,
"maddy",
@@ -37,9 +37,9 @@ class CloudSessionMapperTest {
(short) 11, "Scanning", "scanreporting", (short) 10,
(short) 1, "111", "_parent", "")));
Session session = new CloudSessionMapper(new SessionMenuRenderer()).map(identity);
UserSession session = new CloudSessionMapper(new SessionMenuRenderer()).map(identity);
assertEquals("17", session.getUserID());
assertEquals((short) 17, session.getUserId());
assertEquals("maddy", session.getUsername());
assertEquals("Operations", session.getUserGroupName());
assertEquals("Mayapuri", session.getBranchName());
@@ -49,4 +49,19 @@ class CloudSessionMapperTest {
assertTrue(session.getMenuHtml().contains("Scanning"));
assertTrue(session.getMenuHtml().contains("scanreporting"));
}
@Test
void createsLegacyProjectionWithoutLosingIdentityValues() {
CloudIdentitySession identity = new CloudIdentitySession(
(short) 17, "maddy", "Maddy", (short) 5, "Operations",
(short) 9, "Mayapuri", "MYP", "Delhi", (short) 2,
"Matrix", "MCR", Instant.parse("2026-07-23T06:30:00Z"), List.of());
CloudSessionMapper mapper = new CloudSessionMapper(new SessionMenuRenderer());
matrix.nimble.model.Session legacy = mapper.toLegacy(mapper.map(identity));
assertEquals("17", legacy.getUserID());
assertEquals("9", legacy.getBranchID());
assertEquals("2", legacy.getCompanyID());
}
}

View File

@@ -0,0 +1,70 @@
package matrix.nimble.controller;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import lib.models.UserSession;
import matrix.services.commons.CommonErrorService;
import matrix.services.commons.CommonService;
import org.junit.jupiter.api.Test;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockHttpSession;
import org.springframework.ui.ModelMap;
class AbstractAuthenticatedControllerTest {
private final CommonService commonService = new CommonService();
private final TestController controller = new TestController(
commonService, new CommonErrorService(commonService));
@Test
void grantsAConfiguredMenuRoute() {
MockHttpSession httpSession = new MockHttpSession();
UserSession session = sessionWithRoute("initview");
commonService.storeUserSession(httpSession, session);
AbstractAuthenticatedController.PageAuthorization result = controller.authorize(
"initview", new ModelMap(), httpSession, new MockHttpServletResponse());
assertTrue(result.isGranted());
assertSame(session, result.session());
}
@Test
void returns401ForMissingSessionAnd403ForMissingPage() {
MockHttpServletResponse noSessionResponse = new MockHttpServletResponse();
AbstractAuthenticatedController.PageAuthorization noSession = controller.authorize(
"initview", new ModelMap(), new MockHttpSession(), noSessionResponse);
assertEquals("error", noSession.viewName());
assertEquals(401, noSessionResponse.getStatus());
MockHttpSession httpSession = new MockHttpSession();
commonService.storeUserSession(httpSession, sessionWithRoute("dashboard"));
MockHttpServletResponse deniedResponse = new MockHttpServletResponse();
AbstractAuthenticatedController.PageAuthorization denied = controller.authorize(
"initview", new ModelMap(), httpSession, deniedResponse);
assertEquals("error", denied.viewName());
assertEquals(403, deniedResponse.getStatus());
}
private UserSession sessionWithRoute(String route) {
return UserSession.builder()
.menuHtml("<a onclick=\"SubmitMenuCommand('" + route
+ "','_parent','MenuForm','')\">Page</a>")
.build();
}
private static final class TestController extends AbstractAuthenticatedController {
private TestController(CommonService commonService, CommonErrorService errorService) {
super(commonService, errorService);
}
private PageAuthorization authorize(
String route,
ModelMap model,
MockHttpSession session,
MockHttpServletResponse response) {
return authorizePage(route, model, session, response);
}
}
}

View File

@@ -0,0 +1,28 @@
package matrix.nimble.query;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import com.cygnus.db.QueryDefinitionException;
import com.cygnus.db.QueryType;
import org.junit.jupiter.api.Test;
class CloudQueryDefinitionProviderTest {
@Test
void adaptsEncryptedCloudQueryProviderValueToDbDefinition() {
CloudQueryDefinitionProvider provider = new CloudQueryDefinitionProvider(
queryId -> "select!C0L!select operation_id from operation where type = ?");
var definition = provider.get(513);
assertEquals(513, definition.queryId());
assertEquals(QueryType.SELECT, definition.type());
assertEquals("select operation_id from operation where type = ?", definition.sql());
}
@Test
void preventsLegacyPlaceholderExecution() {
CloudQueryDefinitionProvider provider = new CloudQueryDefinitionProvider(
queryId -> "select!C0L!select * from operation where type = 'val0'");
assertThrows(QueryDefinitionException.class, () -> provider.get(513));
}
}

View File

@@ -0,0 +1,66 @@
package matrix.nimble.security;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.MGF1ParameterSpec;
import java.security.spec.X509EncodedKeySpec;
import java.time.Instant;
import java.util.Base64;
import java.util.UUID;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.OAEPParameterSpec;
import javax.crypto.spec.PSource;
import lib.models.ApplicationDetails;
import lib.models.CaseSaveRequest;
import lib.exceptions.ApplicationException;
import org.junit.jupiter.api.Test;
class PayloadCryptoServiceTest {
@Test
void decryptsBrowserCompatibleEnvelopeAndRejectsReplay() throws Exception {
ObjectMapper mapper = new ObjectMapper().findAndRegisterModules();
PayloadCryptoService service = new PayloadCryptoService(mapper, "", "");
ApplicationDetails details = new ApplicationDetails();
details.setApplicationId(42);
details.setApplicationNumber("APP-42");
String requestId = UUID.randomUUID().toString();
String timestamp = Instant.now().toString();
PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(
new X509EncodedKeySpec(Base64.getUrlDecoder().decode(service.encodedPublicKey())));
KeyGenerator generator = KeyGenerator.getInstance("AES");
generator.init(256);
SecretKey aesKey = generator.generateKey();
byte[] iv = new byte[12];
java.security.SecureRandom.getInstanceStrong().nextBytes(iv);
byte[] aad = String.join("|", service.keyId(), requestId, timestamp)
.getBytes(StandardCharsets.UTF_8);
Cipher payload = Cipher.getInstance("AES/GCM/NoPadding");
payload.init(Cipher.ENCRYPT_MODE, aesKey, new GCMParameterSpec(128, iv));
payload.updateAAD(aad);
byte[] encryptedPayload = payload.doFinal(mapper.writeValueAsBytes(details));
Cipher wrapper = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
wrapper.init(Cipher.ENCRYPT_MODE, publicKey,
new OAEPParameterSpec("SHA-256", "MGF1",
MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT));
byte[] encryptedKey = wrapper.doFinal(aesKey.getEncoded());
Base64.Encoder encoder = Base64.getUrlEncoder().withoutPadding();
CaseSaveRequest request = new CaseSaveRequest(
service.keyId(), encoder.encodeToString(encryptedKey), encoder.encodeToString(iv),
encoder.encodeToString(encryptedPayload), requestId, timestamp);
assertEquals(42, service.decrypt(request, ApplicationDetails.class).getApplicationId());
assertThrows(ApplicationException.class, () -> service.decrypt(request, ApplicationDetails.class));
}
}

View File

@@ -0,0 +1,49 @@
package matrix.nimble.utilities;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.Arrays;
import org.junit.jupiter.api.Test;
class CommonFunctionsTest {
@Test
void dynamicControlIncludesConfiguredValidationMetadata() {
CommonFunctions functions = functions();
functions.DynamicControls(control("validate(this,'t','SplInstruction')"), "");
assertTrue(functions.getGeneratedHtml().contains("data-validation-required='true'"));
assertTrue(functions.getGeneratedHtml().contains("data-validation-format='SplInstruction'"));
}
@Test
void dynamicControlNormalizesMalformedTrailingDateRule() {
CommonFunctions functions = functions();
functions.DynamicControls(control("validate(this,'f','Date)"), "");
assertTrue(functions.getGeneratedHtml().contains("data-validation-required='false'"));
assertTrue(functions.getGeneratedHtml().contains("data-validation-format='Date'"));
}
private CommonFunctions functions() {
CommonFunctions functions = new CommonFunctions();
functions.setPrevControl("");
functions.setDynamicCtrls("");
functions.setGeneratedHtml("");
return functions;
}
private String[] control(String onBlur) {
String[] control = new String[27];
Arrays.fill(control, "");
control[0] = "1";
control[1] = "Dynamic field";
control[2] = "field1";
control[5] = "40";
control[9] = onBlur;
control[14] = "text";
control[17] = "";
control[26] = "1";
return control;
}
}

View File

@@ -0,0 +1,35 @@
package matrix.services.commons;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertSame;
import lib.models.MessageDetails;
import lib.constants.ApplicationMessage;
import matrix.nimble.model.Session;
import org.junit.jupiter.api.Test;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockHttpSession;
import org.springframework.ui.ModelMap;
class CommonErrorServiceTest {
private final CommonService commonService = new CommonService();
private final CommonErrorService errorService = new CommonErrorService(commonService);
@Test
void appliesHttpStatusAndPreservesAnActiveSessionForTheMenu() {
MockHttpSession httpSession = new MockHttpSession();
Session session = new Session();
session.setMenuHtml("<div id='MenuBar'></div>");
commonService.storeSession(httpSession, session);
MessageDetails details = new MessageDetails(ApplicationMessage.ACCESS_DENIED);
MockHttpServletResponse response = new MockHttpServletResponse();
ModelMap model = new ModelMap();
String view = errorService.render(model, response, httpSession, details);
assertEquals("error", view);
assertEquals(403, response.getStatus());
assertSame(details, model.get(CommonErrorService.ERROR_ATTRIBUTE));
assertSame(session, model.get(CommonService.SESSION_ATTRIBUTE));
}
}

View File

@@ -0,0 +1,64 @@
package matrix.services.commons;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import matrix.nimble.model.Session;
import lib.models.UserSession;
import org.junit.jupiter.api.Test;
import org.springframework.mock.web.MockHttpSession;
class CommonServiceTest {
private final CommonService service = new CommonService();
@Test
void storesAndReadsTheAuthenticatedSession() {
MockHttpSession httpSession = new MockHttpSession();
Session session = sessionWithMenu("initview");
service.storeSession(httpSession, session);
assertSame(session, service.getSession(httpSession));
}
@Test
void storesAndReadsTypedUserSession() {
MockHttpSession httpSession = new MockHttpSession();
UserSession session = typedSessionWithMenu("initview");
service.storeUserSession(httpSession, session);
assertSame(session, service.getUserSession(httpSession));
assertTrue(service.hasPageAccess(session, "initview"));
}
@Test
void grantsOnlyAnExactMenuCommandRoute() {
Session session = sessionWithMenu("/matrix/ver/initview?source=menu");
assertTrue(service.hasPageAccess(session, "initview"));
assertFalse(service.hasPageAccess(session, "view"));
assertFalse(service.hasPageAccess(session, "initview-admin"));
}
@Test
void deniesMissingSessionAndMissingMenu() {
assertFalse(service.hasPageAccess((Session) null, "initview"));
assertFalse(service.hasPageAccess(new Session(), "initview"));
}
private Session sessionWithMenu(String route) {
Session session = new Session();
session.setMenuHtml("<a onclick=\"SubmitMenuCommand('" + route
+ "','_parent','MenuForm','')\">Punching</a>");
return session;
}
private UserSession typedSessionWithMenu(String route) {
return UserSession.builder()
.menuHtml("<a onclick=\"SubmitMenuCommand('" + route
+ "','_parent','MenuForm','')\">Punching</a>")
.build();
}
}

View File

@@ -0,0 +1,194 @@
package matrix.services.edp;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import com.cygnus.db.CygnusDbExecutor;
import com.cygnus.db.RowView;
import com.cygnus.db.SqlArrayParameter;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.sql.Date;
import java.time.LocalDate;
import lib.exceptions.ApplicationException;
import lib.models.PunchedRecordsData;
import lib.models.UserSession;
import lib.models.Option;
import matrix.services.commons.CommonService;
import org.junit.jupiter.api.Test;
class PunchingServiceTest {
@Test
void loadsDuplicateDetailsWithAllowlistedQueryAndSessionScope() {
AtomicReference<Integer> query = new AtomicReference<>();
AtomicReference<Object[]> parameters = new AtomicReference<>();
RowView row = row(new LinkedHashMap<>(Map.of("paddr1", "House 1", "pcolony", 42)));
CygnusDbExecutor executor = (CygnusDbExecutor) Proxy.newProxyInstance(
getClass().getClassLoader(), new Class<?>[] {CygnusDbExecutor.class},
(proxy, method, args) -> {
if (method.getName().equals("query") && args.length == 2) {
query.set((Integer) args[0]);
parameters.set(((Object[]) args[1]).clone());
return List.of(row);
}
throw new UnsupportedOperationException(method.toString());
});
PunchingService service = new PunchingService(
new CommonService(), executor, new ObjectMapper());
UserSession session = UserSession.builder()
.companyId((short) 3).branchId((short) 7).build();
var result = service.findDuplicateDetails(" APP-1 ", (short) 38, 21, session);
assertEquals(21, query.get());
assertArrayEquals(new Object[] {"APP-1", (short) 38, (short) 3, (short) 7,
Date.valueOf(LocalDate.now())}, parameters.get());
assertEquals("House 1", result.records().getFirst().get("paddr1"));
assertThrows(ApplicationException.class,
() -> service.findDuplicateDetails("APP-1", (short) 38, 23, session));
}
@Test
void derivesLocalityCompanyScopeFromSessionBranch() {
AtomicReference<Object[]> parameters = new AtomicReference<>();
Map<String, Object> columns = new LinkedHashMap<>();
columns.put("id", 42);
columns.put("location", "Sector 14");
columns.put("pincode", "122001 ");
columns.put("city", "Gurugram");
CygnusDbExecutor executor = (CygnusDbExecutor) Proxy.newProxyInstance(
getClass().getClassLoader(), new Class<?>[] {CygnusDbExecutor.class},
(proxy, method, args) -> {
if (method.getName().equals("query") && args.length == 2) {
assertEquals(13, args[0]);
parameters.set(((Object[]) args[1]).clone());
return List.of(row(columns));
}
throw new UnsupportedOperationException(method.toString());
});
PunchingService service = new PunchingService(
new CommonService(), executor, new ObjectMapper());
UserSession session = UserSession.builder()
.companyId((short) 3).branchId((short) 7).build();
var result = service.findLocalities(" Gurugram ", " Sec ", session);
assertArrayEquals(new Object[] {(short) 7, "Sec", "Gurugram", "Gurugram"},
parameters.get());
assertEquals(42, result.localities().getFirst().id());
assertEquals("122001", result.localities().getFirst().pincode());
}
@Test
void loadsPunchedRecordsAsFormShapedObjectsAndMergesDynamicFields() {
AtomicReference<Object[]> parameters = new AtomicReference<>();
Map<String, Object> columns = new LinkedHashMap<>();
columns.put("case_id", 101);
columns.put("applno", "APP-1");
columns.put("dynamic_fields", "{\"field1\":\"Dealer\",\"field150_2\":\"Note\"}");
RowView row = row(columns);
CygnusDbExecutor executor = (CygnusDbExecutor) Proxy.newProxyInstance(
getClass().getClassLoader(), new Class<?>[] {CygnusDbExecutor.class},
(proxy, method, args) -> {
if (method.getName().equals("query") && args.length == 2) {
assertEquals(24, args[0]);
parameters.set(((Object[]) args[1]).clone());
return List.of(row);
}
throw new UnsupportedOperationException(method.toString());
});
PunchingService service = new PunchingService(
new CommonService(), executor, new ObjectMapper());
UserSession session = UserSession.builder()
.companyId((short) 3).branchId((short) 7).build();
PunchedRecordsData result = service.loadPunchedRecords(
(short) 38, "c4e2680c-fdb0-48cb-aa07-a563aa64cdb9", session);
assertArrayEquals(new Object[] {"c4e2680c-fdb0-48cb-aa07-a563aa64cdb9",
"c4e2680c-fdb0-48cb-aa07-a563aa64cdb9",
"c4e2680c-fdb0-48cb-aa07-a563aa64cdb9", (short) 38, (short) 3, (short) 7},
parameters.get());
assertEquals(101, result.records().getFirst().get("case_id"));
assertEquals("Dealer", result.records().getFirst().get("field1"));
assertEquals("Note", result.records().getFirst().get("field150_2"));
assertEquals(false, result.records().getFirst().containsKey("dynamic_fields"));
}
@Test
void loadsParameterizedOptionsAndNormalizesApplicationTypeGroup() {
RecordingCommonService commonService = new RecordingCommonService();
PunchingService service = new PunchingService(commonService);
Map<String, List<Option>> options = service.loadOptions((short) 5, (short) 1, (short) 38);
assertEquals(List.of(3, 4, 5, 70),
commonService.calls.stream().map(Call::queryId).toList());
assertArrayEquals(new Object[] {(short) 5, (short) 1},
commonService.calls.get(0).parameters());
assertArrayEquals(new Object[] {(short) 38, (short) 1},
commonService.calls.get(1).parameters());
assertEquals((short) 1, commonService.calls.get(2).parameters()[0]);
assertArrayEquals(new Object[] {"CITY", "APPTYPE"},
((SqlArrayParameter) commonService.calls.get(2).parameters()[1]).values());
assertEquals((short) 38, commonService.calls.get(3).parameters()[0]);
assertArrayEquals(new Object[] {"CATEGORY", "PRODUCT"},
((SqlArrayParameter) commonService.calls.get(3).parameters()[1]).values());
assertEquals("Portfolio", options.get("portfolio.").getFirst().getLabel());
assertEquals("Branch", options.get("branch.").getFirst().getLabel());
assertEquals("City", options.get("city.").getFirst().getLabel());
assertEquals("Applicant", options.get("applicationType.").getFirst().getLabel());
assertEquals("Category", options.get("category.").getFirst().getLabel());
assertEquals("Product", options.get("product.").getFirst().getLabel());
assertThrows(UnsupportedOperationException.class,
() -> options.put("other.", List.of()));
}
private static final class RecordingCommonService extends CommonService {
private final List<Call> calls = new ArrayList<>();
@Override
public List<Option> getOptions(Integer queryId, Object[] queryParams) {
calls.add(new Call(queryId, queryParams.clone()));
return switch (queryId) {
case 3 -> List.of(option(38, "Portfolio", "portfolio."));
case 4 -> List.of(option(7, "Branch", "branch."));
case 5 -> List.of(
option("DEL", "City", "city."),
option("APPLICANT", "Applicant", "apptype."));
case 70 -> List.of(
option("DIRECTOR", "Category", "category."),
option("AUTO", "Product", "product."));
default -> List.of();
};
}
}
private static Option option(Object value, String label, String group) {
Option option = new Option();
option.setValue(value);
option.setLabel(label);
option.setGroup(group);
return option;
}
private static RowView row(Map<String, Object> columns) {
return new RowView() {
@Override public Object get(String column) { return columns.get(column); }
@Override public <T> T get(String column, Class<T> type) {
return type.cast(columns.get(column));
}
@Override public Map<String, Object> asMap() { return columns; }
};
}
private record Call(int queryId, Object[] parameters) {}
}

Some files were not shown because too many files have changed in this diff Show More