Case Punching Feature Done

This commit is contained in:
2026-08-02 00:47:00 +05:30
parent 452e6189e4
commit af360d7793
67 changed files with 1431 additions and 179 deletions

View File

@@ -15,6 +15,9 @@ public interface CygnusDbExecutor {
int update(int queryId, Object[] parameters);
int delete(int queryId, Object[] parameters);
<T> T procedure(int queryId, Object[] parameters, Class<T> responseType);
default <T> T procedure(String queryKey, Object[] parameters, Class<T> responseType) {
throw new UnsupportedOperationException("Query keys are not supported by this executor");
}
<T> List<T> procedureRows(int queryId, Object[] parameters, Class<T> responseType);
<T> void stream(int queryId, Object[] parameters, RowMapper<T> mapper, RowConsumer<T> consumer);
<T> T transaction(TransactionCallback<T> callback);

View File

@@ -109,6 +109,15 @@ public final class JdbcCygnusDbExecutor implements CygnusDbExecutor {
return rows.isEmpty() ? null : rows.getFirst();
}
@Override
public <T> T procedure(String queryKey, Object[] parameters, Class<T> responseType) {
QueryDefinition definition = queryProvider.get(queryKey);
if (definition.type() != QueryType.PROCEDURE) throw new QueryDefinitionException(
"Query " + queryKey + " is " + definition.type() + ", not " + QueryType.PROCEDURE);
DbResult<T> result = executeRowsOrCount(definition, parameters, responseType);
return result.rows().isEmpty() ? null : result.rows().getFirst();
}
@Override
public <T> List<T> procedureRows(int queryId, Object[] parameters, Class<T> responseType) {
DbResult<T> result = executeRowsOrCount(

View File

@@ -3,4 +3,7 @@ package com.cygnus.db;
@FunctionalInterface
public interface QueryDefinitionProvider {
QueryDefinition get(int queryId);
default QueryDefinition get(String queryKey) {
throw new UnsupportedOperationException("Query keys are not supported by this provider");
}
}

View File

@@ -0,0 +1,293 @@
-- Atomic application initiation save.
BEGIN;
CREATE OR REPLACE FUNCTION public.save_application_details(
p_application jsonb,
p_company_id smallint,
p_branch_id smallint,
p_user_id smallint
)
RETURNS TABLE(operation text, application_id integer, mv_code text, internal_uuid text)
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public, pg_temp
AS $function$
DECLARE
d record;
v_case_id integer;
v_uuid text;
v_mvcode text;
v_operation text;
v_mvnumber integer;
v_mvprefix text;
v_batch text;
v_earlier smallint := 1;
v_tele_denied smallint := 0;
v_reference_denied smallint := 0;
v_now timestamp without time zone := clock_timestamp();
BEGIN
IF p_application IS NULL OR p_company_id IS NULL OR p_branch_id IS NULL OR p_user_id IS NULL THEN
RAISE EXCEPTION 'Incomplete case context' USING ERRCODE = '22023';
END IF;
SELECT * INTO d
FROM jsonb_to_record(p_application) AS x(
"applicationId" integer, "portfolioId" smallint, "bankBranchId" smallint,
"applicationNumber" text, "bankCode" text, "product" text, "loanAmount" text,
"customerName" text, "fatherName" text, "applicationType" text, "category" text,
"dateOfBirth" text, "contactPerson" text, "mobileNumber" text,
"specialInstruction" text, "residenceVerification" boolean,
"residenceTelephoneVerification" boolean, "officeVerification" boolean,
"officeTelephoneVerification" boolean, "propertyVerification" boolean,
"referenceVerification" boolean, "documentVerification" boolean,
"residenceCoApplicant" boolean, "residenceCoProprietor" boolean,
"officeCoProprietor" boolean, "sameResidenceAddress" boolean,
"sameOfficeAddress" boolean, "samePropertyAddress" boolean,
"residenceAddress1" text, "residenceAddress2" text, "residenceAddress3" text,
"residenceLandmark" text, "residenceColonyId" integer, "residenceCity" text,
"residencePincode" text, "residencePhone" text, "companyName" text,
"officeAddress1" text, "officeAddress2" text, "officeAddress3" text,
"officeLandmark" text, "officeColonyId" integer, "officeCity" text,
"officePincode" text, "department" text, "designation" text,
"officePhone" text, "extension" text, "propertyAddress1" text,
"propertyAddress2" text, "propertyAddress3" text, "propertyLandmark" text,
"propertyColonyId" integer, "propertyCity" text, "propertyPincode" text,
"referenceName1" text, "referenceAddress1" text, "referenceContactNumber1" text,
"referenceName2" text, "referenceAddress2" text, "referenceContactNumber2" text,
"autoCutOff" boolean, "formMode" integer
);
IF d."portfolioId" IS NULL OR d."portfolioId" <= 0
OR NOT EXISTS (
SELECT 1 FROM portfolio p
WHERE p.portfolio_id = d."portfolioId"
AND p.company_id = p_company_id
AND p.branch_id = p_branch_id
AND p.isactive = 1) THEN
RAISE EXCEPTION 'Portfolio is not available to this session' USING ERRCODE = '42501';
END IF;
IF coalesce(trim(d."applicationNumber"), '') = ''
OR coalesce(d."bankBranchId", 0) <= 0
OR coalesce(trim(d."product"), '') = ''
OR coalesce(trim(d."customerName"), '') = ''
OR coalesce(trim(d."applicationType"), '') = '' THEN
RAISE EXCEPTION 'Required case fields are missing' USING ERRCODE = '22023';
END IF;
IF NOT (coalesce(d."residenceVerification", false)
OR coalesce(d."residenceTelephoneVerification", false)
OR coalesce(d."officeVerification", false)
OR coalesce(d."officeTelephoneVerification", false)
OR coalesce(d."propertyVerification", false)
OR coalesce(d."referenceVerification", false)
OR coalesce(d."documentVerification", false)) THEN
RAISE EXCEPTION 'At least one verification is required' USING ERRCODE = '22023';
END IF;
v_case_id := coalesce(d."applicationId", 0);
IF v_case_id = 0 THEN
UPDATE mvcode
SET lastmvcode = lastmvcode + 1
WHERE portfolio_id = d."portfolioId"
RETURNING lastmvcode, trim(mvcprefix) INTO v_mvnumber, v_mvprefix;
IF NOT FOUND THEN
RAISE EXCEPTION 'MV code configuration is missing' USING ERRCODE = '23503';
END IF;
v_mvcode := coalesce(v_mvprefix, '') || v_mvnumber;
v_uuid := gen_random_uuid()::text;
INSERT INTO main (
portfolio_id, bank_branch_id, mvcode, applno, bankcode, product, loanamount,
customername, fathername, apptype, category, dob, contactperson, mobileno,
specialinst, rv, rtv, ov, otv, pv, refv, docv, rco, rcp, ocp, sradd, soadd,
spadd, 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, field1, field2, field3, field4, field5, field6,
field7, field8, field9, field10, field11, field12, dtfield1, receivedate,
addedby, addedon, company_id, branch_id, uuid)
VALUES (
d."portfolioId", coalesce(d."bankBranchId", 0), v_mvcode,
trim(d."applicationNumber"), nullif(trim(d."bankCode"), ''), trim(d."product"),
nullif(trim(d."loanAmount"), ''), trim(d."customerName"),
nullif(trim(d."fatherName"), ''), trim(d."applicationType"),
nullif(trim(d."category"), ''), nullif(trim(d."dateOfBirth"), ''),
nullif(trim(d."contactPerson"), ''), nullif(trim(d."mobileNumber"), ''),
coalesce(d."specialInstruction", ''),
coalesce(d."residenceVerification", false)::int,
coalesce(d."residenceTelephoneVerification", false)::int,
coalesce(d."officeVerification", false)::int,
coalesce(d."officeTelephoneVerification", false)::int,
coalesce(d."propertyVerification", false)::int,
coalesce(d."referenceVerification", false)::int,
coalesce(d."documentVerification", false)::int,
coalesce(d."residenceCoApplicant", false)::int,
coalesce(d."residenceCoProprietor", false)::int,
coalesce(d."officeCoProprietor", false)::int,
coalesce(d."sameResidenceAddress", false)::int,
coalesce(d."sameOfficeAddress", false)::int,
coalesce(d."samePropertyAddress", false)::int,
d."residenceAddress1", d."residenceAddress2", d."residenceAddress3",
d."residenceLandmark", coalesce(d."residenceColonyId", 0), d."residenceCity",
d."residencePincode", d."residencePhone", d."companyName", d."officeAddress1",
d."officeAddress2", d."officeAddress3", d."officeLandmark",
coalesce(d."officeColonyId", 0), d."officeCity", d."officePincode",
d."department", d."designation", d."officePhone", d."extension",
d."propertyAddress1", d."propertyAddress2", d."propertyAddress3",
d."propertyLandmark", coalesce(d."propertyColonyId", 0), d."propertyCity",
d."propertyPincode", d."referenceName1", d."referenceAddress1",
d."referenceContactNumber1", d."referenceName2", d."referenceAddress2",
d."referenceContactNumber2", p_application->'dynamicFields'->>'field1',
p_application->'dynamicFields'->>'field2', p_application->'dynamicFields'->>'field3',
p_application->'dynamicFields'->>'field4', p_application->'dynamicFields'->>'field5',
p_application->'dynamicFields'->>'field6', p_application->'dynamicFields'->>'field7',
p_application->'dynamicFields'->>'field8', p_application->'dynamicFields'->>'field9',
p_application->'dynamicFields'->>'field10', p_application->'dynamicFields'->>'field11',
p_application->'dynamicFields'->>'field12',
nullif(p_application->'dynamicFields'->>'dtfield1', '')::date,
current_date, p_user_id, v_now, p_company_id, p_branch_id, v_uuid)
RETURNING main.case_id INTO v_case_id;
INSERT INTO main_operations (uuid, company_id, branch_id, islocked, portfolio_id)
VALUES (v_uuid, p_company_id, p_branch_id, 0, d."portfolioId");
v_operation := 'INSERT';
ELSE
SELECT m.uuid, m.mvcode INTO v_uuid, v_mvcode
FROM main m
WHERE m.case_id = v_case_id
AND m.company_id = p_company_id
AND m.branch_id = p_branch_id
AND m.portfolio_id = d."portfolioId"
AND m.isdeleted = 0
FOR UPDATE;
IF NOT FOUND THEN
RAISE EXCEPTION 'Case is not available to this session' USING ERRCODE = '42501';
END IF;
UPDATE main SET
bank_branch_id=coalesce(d."bankBranchId",0), applno=trim(d."applicationNumber"),
bankcode=nullif(trim(d."bankCode"),''), product=trim(d."product"),
loanamount=nullif(trim(d."loanAmount"),''), customername=trim(d."customerName"),
fathername=nullif(trim(d."fatherName"),''), apptype=trim(d."applicationType"),
category=nullif(trim(d."category"),''), dob=nullif(trim(d."dateOfBirth"),''),
contactperson=nullif(trim(d."contactPerson"),''), mobileno=nullif(trim(d."mobileNumber"),''),
specialinst=coalesce(d."specialInstruction",''),
rv=coalesce(d."residenceVerification",false)::int,
rtv=coalesce(d."residenceTelephoneVerification",false)::int,
ov=coalesce(d."officeVerification",false)::int,
otv=coalesce(d."officeTelephoneVerification",false)::int,
pv=coalesce(d."propertyVerification",false)::int,
refv=coalesce(d."referenceVerification",false)::int,
docv=coalesce(d."documentVerification",false)::int,
rco=coalesce(d."residenceCoApplicant",false)::int,
rcp=coalesce(d."residenceCoProprietor",false)::int,
ocp=coalesce(d."officeCoProprietor",false)::int,
sradd=coalesce(d."sameResidenceAddress",false)::int,
soadd=coalesce(d."sameOfficeAddress",false)::int,
spadd=coalesce(d."samePropertyAddress",false)::int,
raddr1=d."residenceAddress1", raddr2=d."residenceAddress2", raddr3=d."residenceAddress3",
rlandmark=d."residenceLandmark", rcolony=coalesce(d."residenceColonyId",0),
rcity=d."residenceCity", rpincode=d."residencePincode", rphone=d."residencePhone",
companyname=d."companyName", oaddr1=d."officeAddress1", oaddr2=d."officeAddress2",
oaddr3=d."officeAddress3", olandmark=d."officeLandmark",
ocolony=coalesce(d."officeColonyId",0), ocity=d."officeCity",
opincode=d."officePincode", department=d."department", designation=d."designation",
ophone=d."officePhone", extension=d."extension", paddr1=d."propertyAddress1",
paddr2=d."propertyAddress2", paddr3=d."propertyAddress3",
plandmark=d."propertyLandmark", pcolony=coalesce(d."propertyColonyId",0),
pcity=d."propertyCity", ppincode=d."propertyPincode", refname1=d."referenceName1",
refaddress1=d."referenceAddress1", refcontactno1=d."referenceContactNumber1",
refname2=d."referenceName2", refaddress2=d."referenceAddress2",
refcontactno2=d."referenceContactNumber2", field1=p_application->'dynamicFields'->>'field1',
field2=p_application->'dynamicFields'->>'field2', field3=p_application->'dynamicFields'->>'field3',
field4=p_application->'dynamicFields'->>'field4', field5=p_application->'dynamicFields'->>'field5',
field6=p_application->'dynamicFields'->>'field6', field7=p_application->'dynamicFields'->>'field7',
field8=p_application->'dynamicFields'->>'field8', field9=p_application->'dynamicFields'->>'field9',
field10=p_application->'dynamicFields'->>'field10', field11=p_application->'dynamicFields'->>'field11',
field12=p_application->'dynamicFields'->>'field12',
dtfield1=nullif(p_application->'dynamicFields'->>'dtfield1','')::date,
addedon=CASE WHEN addedby=0 THEN v_now ELSE addedon END,
addedby=CASE WHEN addedby=0 THEN p_user_id ELSE addedby END,
lasteditedon=v_now, lasteditedby=p_user_id
WHERE main.case_id=v_case_id;
IF coalesce(d."formMode", 0) = 2 THEN
INSERT INTO caseedit_history(user_id, operation, uuid, operationon)
VALUES (p_user_id, 'CASEEDIT', v_uuid, v_now);
UPDATE temp_reporting SET
bank_branch_id=coalesce(d."bankBranchId",0),
applno=trim(d."applicationNumber"), product=trim(d."product"),
customername=trim(d."customerName"), apptype=trim(d."applicationType"),
category=nullif(trim(d."category"),''),
rv=coalesce(d."residenceVerification",false)::int,
rtv=coalesce(d."residenceTelephoneVerification",false)::int,
ov=coalesce(d."officeVerification",false)::int,
otv=coalesce(d."officeTelephoneVerification",false)::int,
pv=coalesce(d."propertyVerification",false)::int,
refv=coalesce(d."referenceVerification",false)::int,
docv=coalesce(d."documentVerification",false)::int,
rco=coalesce(d."residenceCoApplicant",false)::int,
rcp=coalesce(d."residenceCoProprietor",false)::int,
ocp=coalesce(d."officeCoProprietor",false)::int,
sradd=coalesce(d."sameResidenceAddress",false)::int,
soadd=coalesce(d."sameOfficeAddress",false)::int,
spadd=coalesce(d."samePropertyAddress",false)::int
WHERE uuid=v_uuid;
IF coalesce(d."residenceVerification", false) THEN
INSERT INTO residence(uuid)
SELECT v_uuid WHERE NOT EXISTS (SELECT 1 FROM residence WHERE uuid=v_uuid);
END IF;
IF coalesce(d."officeVerification", false) THEN
INSERT INTO office(uuid)
SELECT v_uuid WHERE NOT EXISTS (SELECT 1 FROM office WHERE uuid=v_uuid);
END IF;
IF coalesce(d."residenceTelephoneVerification", false)
OR coalesce(d."officeTelephoneVerification", false) THEN
SELECT coalesce(max(isdenied), 0) INTO v_tele_denied
FROM denied_process
WHERE portfolio_id=d."portfolioId" AND process_id=14 AND isdenied=1;
IF v_tele_denied=0 THEN
INSERT INTO telecalling(uuid)
SELECT v_uuid WHERE NOT EXISTS (SELECT 1 FROM telecalling WHERE uuid=v_uuid);
ELSE
UPDATE temp_reporting SET rtv=0, otv=0 WHERE uuid=v_uuid;
END IF;
END IF;
IF coalesce(d."referenceVerification", false) THEN
SELECT coalesce(max(isdenied), 0) INTO v_reference_denied
FROM denied_process
WHERE portfolio_id=d."portfolioId" AND process_id=15 AND isdenied=1;
IF v_reference_denied=0 THEN
INSERT INTO refrencecalling(uuid)
SELECT v_uuid WHERE NOT EXISTS (SELECT 1 FROM refrencecalling WHERE uuid=v_uuid);
ELSE
UPDATE temp_reporting SET refv=0 WHERE uuid=v_uuid;
END IF;
END IF;
IF coalesce(d."propertyVerification", false) THEN
INSERT INTO property(uuid)
SELECT v_uuid WHERE NOT EXISTS (SELECT 1 FROM property WHERE uuid=v_uuid);
END IF;
END IF;
v_operation := 'UPDATE';
END IF;
IF coalesce(d."autoCutOff", false) THEN
v_batch := CASE WHEN localtime <= time '14:30' THEN 'AM' ELSE 'PM' END;
IF d."portfolioId" IN (68,129) THEN v_earlier := -2; END IF;
UPDATE main_operations SET allocation=1, sms=1, telesheet=-2,
earlier=v_earlier, negative=v_earlier, cutoffby=p_user_id,
islocked=p_user_id, batch=v_batch, cutoffon=v_now
WHERE (cutoffby IS NULL OR cutoffby=0) AND uuid=v_uuid;
END IF;
RETURN QUERY SELECT v_operation, v_case_id, v_mvcode, v_uuid;
END;
$function$;
REVOKE ALL ON FUNCTION public.save_application_details(jsonb,smallint,smallint,smallint) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION public.save_application_details(jsonb,smallint,smallint,smallint) TO postgres;
COMMIT;