CREATE OR REPLACE
FUNCTION FN_TF_LOAN_INT_INFO
	(
		FIN_ENTITY_CODE FINENT.FIN_ENTITY%TYPE,
		ACCT_PRD ACCTPRD.CODE%TYPE,
		PRD_CODE__FR PERIOD.CODE%TYPE,
		PRD_CODE__TO PERIOD.CODE%TYPE,
		SITE_CODE__FR SITE.SITE_CODE%TYPE,
		SITE_CODE__TO SITE.SITE_CODE%TYPE,
		EMP_CODE__FR EMPLOYEE.EMP_CODE%TYPE, 
		EMP_CODE__TO EMPLOYEE.EMP_CODE%TYPE,
		EFF_INT_RATE LOANS.INTEREST%TYPE
	)
RETURN TFT_LOAN_INT_INFO 
PIPELINED IS 
OUT_REC TFO_LOAN_INT_INFO := TFO_LOAN_INT_INFO(	NULL,NULL,NULL,NULL,NULL,NULL,NULL,
		NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
		NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);

LI_CNT NUMBER(6);
LI_CNT1 NUMBER(6);
LI_CNT2 NUMBER(6);
EMI_NO NUMBER(6);
LC_LOAN_OP_BAL LOANS.LOAN_AMT%TYPE;
LC_LOAN_RECO LOANS.LOAN_AMT%TYPE;
LD_LOAN_CLOUSRE_DATE DATE;
EMI_PRD_CODE PERIOD.CODE%TYPE;
PV_FACTOR NUMBER(12,4);
PRESENT_VALUE LOANS.LOAN_AMT%TYPE;
TOT_PRESENT_VALUE LOANS.LOAN_AMT%TYPE;
AMORTISED_COST_OP_BAL LOANS.LOAN_AMT%TYPE;
INTEREST_AT_EFF_RATE LOANS.LOAN_AMT%TYPE;
AMORTISED_COST_CL_BAL LOANS.LOAN_AMT%TYPE;
EMP_BENEFIT LOANS.LOAN_AMT%TYPE;
DIFF_PRINC_DEDN LOANS.LOAN_AMT%TYPE;
LC_PRINC_DEDN LOANS.LOAN_AMT%TYPE;
LC_INT_DEDN LOANS.LOAN_AMT%TYPE;
LC_OTH_RECOVERY LOANS.LOAN_AMT%TYPE;
LC_EFF_INT_RATE LOANS.INTEREST%TYPE;

CURSOR LOAN_INFO IS 
	SELECT 
	LN.EMP_CODE AS EMP_CODE ,
	TRIM(EM.EMP_FNAME) || ' ' || TRIM(EM.EMP_MNAME) || TRIM(EM.EMP_LNAME) AS EMP_FULL_NAME,
	EM.PAY_SITE AS PAY_SITE,
	EM.CCTR_CODE__SAL AS CCTR_CODE__SAL,
	LN.LOAN_NO AS LOAN_NO,
	LN.SCHEME_NO SCHEME_NO,
	LN.ISSUE_DATE AS ISSUE_DATE,
	LN.START_RECO AS START_RECO,
	LN.TERM AS TERM,
	LN.LOAN_AMT AS LOAN_AMT,
	LN.INTEREST AS INTEREST,
	LN.MON_INST AS MON_INST,
	LN.INT_TERM AS INT_TERM,
	LN.INTEREST_AMT AS INTEREST_AMT,
	LN.RECOVER_AMT AS RECOVER_AMT,
	LN.APPR_DATE AS APPR_DATE,
	LN.BALANCE_AMT AS BALANCE_AMT,
	LN.DATE__BALANCE AS DATE__BALANCE,
	LN.DATE__INTEREST AS DATE__INTEREST,
	LN.LOAN_TYPE AS LOAN_TYPE,
	LN.ACT_TERM AS ACT_TERM,
	AP.FR_DATE AS FY_FROM_DATE,
	AP.TO_DATE AS FY_TO_DATE,
	LS.AD_CODE__INT AS AD_CODE__INT,
	LS.AD_CODE__DED AS AD_CODE__DED,
	LS.SCHEME_TYPE AS SCHEME_TYPE
	FROM LOANS LN, EMPLOYEE EM, SITE SM, ACCTPRD AP, LOAN_SCHEME LS 
	WHERE EM.EMP_CODE = LN.EMP_CODE 
	AND LN.EMP_CODE >= EMP_CODE__FR 
	AND LN.EMP_CODE <= EMP_CODE__TO 
	AND EM.PAY_SITE >= SITE_CODE__FR 
	AND EM.PAY_SITE <= SITE_CODE__TO 
	AND SM.SITE_CODE = EM.PAY_SITE 
	AND SM.FIN_ENTITY = FIN_ENTITY_CODE 
	AND LN.ISSUE_DATE <= AP.TO_DATE 
	AND AP.CODE = ACCT_PRD 
	AND LN.STATUS IN ('A','E')
	AND LS.SCHEME_NO = LN.SCHEME_NO 
	AND LS.SCHEME_TYPE NOT IN ('A','B');

CURSOR PRD_INFO(START_DATE DATE) IS SELECT CODE,FR_DATE,TO_DATE FROM PERIOD WHERE TO_DATE >= START_DATE ORDER BY TO_DATE;

BEGIN
	LI_CNT2 := 0;
	FOR I IN LOAN_INFO
	LOOP
		LI_CNT2 := LI_CNT2 + 1;
		LI_CNT := 0;
		LC_LOAN_OP_BAL := I.LOAN_AMT;
		SELECT SUM(AMOUNT) INTO LC_LOAN_RECO FROM LOAN_REG WHERE LOAN_NO = I.LOAN_NO 
		AND TRAN_DATE < I.FY_FROM_DATE;
		IF LC_LOAN_RECO IS NOT NULL THEN 
			LC_LOAN_OP_BAL := LC_LOAN_OP_BAL - LC_LOAN_RECO;
		END IF;
		IF LC_LOAN_OP_BAL > 0 THEN
			EMI_NO := 0;
			TOT_PRESENT_VALUE := 0;
			LC_LOAN_OP_BAL := I.LOAN_AMT;
			SELECT SUM(INT_RATE) INTO LC_EFF_INT_RATE FROM LOANSCHEME_INT_RATE WHERE SCHEME_TYPE = I.SCHEME_TYPE AND I.ISSUE_DATE BETWEEN EFF_FROM AND VALID_UPTO;
			IF LC_EFF_INT_RATE IS NULL THEN 
				LC_EFF_INT_RATE := CASE WHEN EFF_INT_RATE IS NULL OR EFF_INT_RATE <= 0 THEN I.INTEREST ELSE EFF_INT_RATE END;
			END IF;

			FOR J IN PRD_INFO(I.ISSUE_DATE)
			LOOP
				IF LC_LOAN_OP_BAL > 0 THEN
					EMI_NO := EMI_NO + 1;
					LI_CNT1 := 0;
					SELECT COUNT(1) INTO LI_CNT1 FROM PAYROLL WHERE EMP_CODE = I.EMP_CODE AND PRD_CODE = J.CODE;
					PV_FACTOR := 0;
					PRESENT_VALUE := 0;
					LC_OTH_RECOVERY := 0;
					LC_INT_DEDN := 0;
					LC_PRINC_DEDN := 0;
					IF LI_CNT1 > 0 THEN
						SELECT AMOUNT INTO LC_PRINC_DEDN FROM PAYROLLDET WHERE EMP_CODE = I.EMP_CODE AND PRD_CODE = J.CODE AND ((REF_TYPE = 'L' AND REF_NO = I.LOAN_NO) OR AD_CODE = I.AD_CODE__DED);
						SELECT AMOUNT INTO LC_INT_DEDN FROM PAYROLLDET WHERE EMP_CODE = I.EMP_CODE AND PRD_CODE = J.CODE AND ((REF_TYPE = 'N' AND REF_NO = I.LOAN_NO) OR AD_CODE = I.AD_CODE__INT);
					ELSE
						LC_INT_DEDN := ROUND((LC_LOAN_OP_BAL * I.INTEREST / 100) / ((I.FY_TO_DATE - I.FY_FROM_DATE) + 1) * ((J.TO_DATE - CASE WHEN I.ISSUE_DATE > J.FR_DATE THEN I.ISSUE_DATE ELSE J.FR_DATE END) + 1),2);
						IF TRIM(I.INT_TERM) = 'EMI' THEN
							LC_PRINC_DEDN := I.MON_INST - LC_INT_DEDN;
						ELSE
							LC_PRINC_DEDN := I.MON_INST;
						END IF;
					END IF;
					IF LC_PRINC_DEDN > LC_LOAN_OP_BAL THEN
						LC_PRINC_DEDN := LC_LOAN_OP_BAL;
					END IF;

					SELECT SUM(AMOUNT) INTO LC_OTH_RECOVERY FROM LOAN_REG WHERE LOAN_NO = I.LOAN_NO AND TRAN_DATE BETWEEN J.FR_DATE AND J.TO_DATE AND TRAN_TYPE NOT IN ('P');
					IF LC_OTH_RECOVERY IS NULL THEN 
						LC_OTH_RECOVERY := 0;
					END IF;
					PV_FACTOR := ROUND(1 / POWER((1 + ROUND(LC_EFF_INT_RATE / 1200 , 4)),EMI_NO),4);
					PRESENT_VALUE := ROUND((LC_PRINC_DEDN + LC_INT_DEDN + LC_OTH_RECOVERY) * PV_FACTOR , 2);
					TOT_PRESENT_VALUE := TOT_PRESENT_VALUE + PRESENT_VALUE;
					LC_LOAN_OP_BAL := LC_LOAN_OP_BAL - LC_PRINC_DEDN - LC_OTH_RECOVERY;
				ELSE
					EXIT;
				END IF;
			END LOOP;

			LC_LOAN_OP_BAL := I.LOAN_AMT;
			PV_FACTOR := 0;
			PRESENT_VALUE := 0;
			LC_OTH_RECOVERY := 0;
			LC_INT_DEDN := 0;
			LC_PRINC_DEDN := 0;
			EMI_NO := 0;
			FOR J IN PRD_INFO(I.ISSUE_DATE)
			LOOP
				IF LC_LOAN_OP_BAL > 0 THEN
					LC_OTH_RECOVERY := 0;
					EMI_NO := EMI_NO + 1;
					LI_CNT1 := 0;
					SELECT COUNT(1) INTO LI_CNT1 FROM PAYROLL WHERE EMP_CODE = I.EMP_CODE AND PRD_CODE = J.CODE;
					LC_PRINC_DEDN := 0;
					LC_INT_DEDN := 0;
					IF LI_CNT1 > 0 THEN
						SELECT AMOUNT INTO LC_PRINC_DEDN FROM PAYROLLDET WHERE EMP_CODE = I.EMP_CODE AND PRD_CODE = J.CODE AND ((REF_TYPE = 'L' AND REF_NO = I.LOAN_NO) OR AD_CODE = I.AD_CODE__DED);
						SELECT AMOUNT INTO LC_INT_DEDN FROM PAYROLLDET WHERE EMP_CODE = I.EMP_CODE AND PRD_CODE = J.CODE AND ((REF_TYPE = 'N' AND REF_NO = I.LOAN_NO) OR AD_CODE = I.AD_CODE__INT);
					ELSE
						LC_INT_DEDN := ROUND((LC_LOAN_OP_BAL * I.INTEREST / 100) / ((I.FY_TO_DATE - I.FY_FROM_DATE) + 1) * ((J.TO_DATE - CASE WHEN I.ISSUE_DATE > J.FR_DATE THEN I.ISSUE_DATE ELSE J.FR_DATE END) + 1),2);
						IF TRIM(I.INT_TERM) = 'EMI' THEN
							LC_PRINC_DEDN := I.MON_INST - LC_INT_DEDN;
						ELSE
							LC_PRINC_DEDN := I.MON_INST;
						END IF;
					END IF;
					IF LC_PRINC_DEDN > LC_LOAN_OP_BAL THEN
						LC_PRINC_DEDN := LC_LOAN_OP_BAL;
					END IF;

					SELECT SUM(AMOUNT) INTO LC_OTH_RECOVERY FROM LOAN_REG WHERE LOAN_NO = I.LOAN_NO AND TRAN_DATE BETWEEN J.FR_DATE AND J.TO_DATE AND TRAN_TYPE NOT IN ('P');
					IF LC_OTH_RECOVERY IS NULL THEN 
						LC_OTH_RECOVERY := 0;
					END IF;
					AMORTISED_COST_OP_BAL := CASE WHEN EMI_NO = 1 THEN TOT_PRESENT_VALUE ELSE AMORTISED_COST_CL_BAL END;

					INTEREST_AT_EFF_RATE := ROUND((AMORTISED_COST_OP_BAL * LC_EFF_INT_RATE / 100) / ((I.FY_TO_DATE - I.FY_FROM_DATE) + 1) * ((J.TO_DATE - CASE WHEN I.ISSUE_DATE > J.FR_DATE THEN I.ISSUE_DATE ELSE J.FR_DATE END) + 1),2);

					AMORTISED_COST_CL_BAL := AMORTISED_COST_OP_BAL + INTEREST_AT_EFF_RATE - (LC_PRINC_DEDN + LC_OTH_RECOVERY + LC_INT_DEDN);

					PV_FACTOR := ROUND(1 / POWER((1 + ROUND(LC_EFF_INT_RATE / 1200 , 4)),EMI_NO),4);
					PRESENT_VALUE := ROUND((LC_PRINC_DEDN + LC_INT_DEDN + LC_OTH_RECOVERY) * PV_FACTOR , 2);

					EMP_BENEFIT := INTEREST_AT_EFF_RATE - LC_INT_DEDN;
					DIFF_PRINC_DEDN := AMORTISED_COST_CL_BAL - (LC_LOAN_OP_BAL - (LC_PRINC_DEDN + LC_INT_DEDN));
					OUT_REC.EMP_CODE := I.EMP_CODE; 
					OUT_REC.EMP_FULL_NAME := I.EMP_FULL_NAME; 
					OUT_REC.PAY_SITE := I.PAY_SITE; 
					OUT_REC.CCTR_CODE__SAL := I.CCTR_CODE__SAL; 
					OUT_REC.LOAN_NO := I.LOAN_NO; 
					OUT_REC.SCHEME_NO := I.SCHEME_NO; 
					OUT_REC.ISSUE_DATE := I.ISSUE_DATE; 
					OUT_REC.TERM := I.TERM; 
					OUT_REC.LOAN_AMT := I.LOAN_AMT; 
					OUT_REC.INTEREST := I.INTEREST; 
					OUT_REC.MON_INST := (LC_PRINC_DEDN + LC_INT_DEDN); 
					OUT_REC.INT_TERM := I.INT_TERM; 
					OUT_REC.INTEREST_AMT := LC_INT_DEDN; 
					OUT_REC.RECOVER_AMT := LC_OTH_RECOVERY; 
					OUT_REC.APPR_DATE := I.APPR_DATE; 
					OUT_REC.BALANCE_AMT := LC_LOAN_OP_BAL; 
					OUT_REC.DATE__BALANCE := I.DATE__BALANCE; 
					OUT_REC.DATE__INTEREST := I.DATE__INTEREST; 
					OUT_REC.LOAN_TYPE := I.LOAN_TYPE; 
					OUT_REC.LOAN_CLOUSRE_DATE := LD_LOAN_CLOUSRE_DATE; 
					OUT_REC.ISA_EFF_INT_RATE := LC_EFF_INT_RATE; 
					OUT_REC.EMI_NO := EMI_NO; 
					OUT_REC.EMI_PRD_CODE := J.CODE; 
					OUT_REC.PV_FACTOR := PV_FACTOR; 
					OUT_REC.PRESENT_VALUE := PRESENT_VALUE; 
					OUT_REC.AMORTISED_COST_OP_BAL := AMORTISED_COST_OP_BAL; 
					OUT_REC.INTEREST_AT_EFF_RATE := INTEREST_AT_EFF_RATE; 
					OUT_REC.AMORTISED_COST_CL_BAL := AMORTISED_COST_CL_BAL; 
					OUT_REC.EMP_BENEFIT := EMP_BENEFIT; 
					OUT_REC.DIFF_PRINC_DEDN := DIFF_PRINC_DEDN; 
					OUT_REC.PRINC_DEDN := LC_PRINC_DEDN; 
					OUT_REC.PRINC_DEDN := LC_PRINC_DEDN; 
					LC_LOAN_OP_BAL := LC_LOAN_OP_BAL - LC_PRINC_DEDN - LC_OTH_RECOVERY;
					pipe row ( out_rec ); 
				ELSE
					EXIT;
				END IF;
			END LOOP;
		END IF;
	END LOOP;

	RETURN ;
END;
/
