@if (loadingApplication) {
Loading application…
}
@if (application; as a) {
CREDIT · LOAN ORIGINATION · {{ a.branchName | uppercase }}
{{ a.applicationNo }} — {{ a.applicantName }}
{{ statusLabels[a.overallStatus] }}
{{ a.productName }} · ₹{{ a.requestedAmount | number: '1.0-0' }} · Applied {{ a.applicationDate }} ·
{{ progress(a) }}% through the sanctioning workflow.
Branch
{{ a.branchName }}
Channel
{{ a.channel === 'BC' ? a.bcAgentName : a.channel === 'SELF_APPLY' ? 'Self-Apply (Digital)' : 'Branch' }}
Customer Type
{{ a.customerType === 'EXISTING' ? 'Existing Customer' : 'New Customer' }}
Tenure / Rate
{{ a.tenureMonths }} months @ {{ a.interestRate }}%
Monthly Income / Eligible Amount
₹{{ a.monthlyIncome | number: '1.0-0' }} / ₹{{ a.eligibleLoanAmount | number: '1.0-0' }}
Sanctioning Authority
{{ sanctioningAuthorityOf(a) }}
Share Member
@if (a.clientId) {
@if (loadingShareAccounts) {
Checking membership…
} @else if (realShareAccounts.length > 0) {
@for (sa of realShareAccounts; track sa.id) {
{{ sa.accountNo }} — {{ sa.productName }}
}
} @else {
Not a Member
Allot Shares
}
} @else if (a.isShareMember) {
Yes — {{ a.shareCertNo }} (since {{ a.shareMemberSince }})
} @else {
Not a Member
Allot Shares
}
@if (a.coBorrowerRequired) {
Co-Borrower
{{ a.coBorrowerName }}
@if (a.coBorrowerWanted && a.coBorrowerRelationship) {
({{ a.coBorrowerRelationship }})
}
}
@if (a.guarantorRequired) {
Guarantor
{{ a.guarantorName }}
}
Guarantors — {{ guarantorsNeeded(app) }} required{{
app.guarantorMustBeMember === false ? '' : ', each must be an existing share member'
}}
@for (i of guarantorSlots(app); track i) {
@if (guarantorAt(app, i); as g) {
Guarantor {{ i + 1 }}
{{ g.name }}
Change
@if (g.hasShareAccount) {
Share Member — Verified
@if (g.shareAccountNos?.length) {
{{ g.shareAccountNos!.join(', ') }}
}
} @else if (loadingGuarantorShareCheck) {
Checking share membership…
} @else if (app.guarantorMustBeMember === false) {
Named
} @else {
No Share Account Found
This client has no active share account — a guarantor must already be a bank member. Change the
guarantor.
}
} @else {
Guarantor {{ i + 1 }} — search existing client
@if (guarantorSlotSearching === i) {
@if (searchingGuarantor) {
Searching…
} @else if (guarantorSearchText.length >= 2 && guarantorSearchResults.length === 0) {
No clients found.
}
@if (guarantorSearchResults.length > 0) {
@for (client of guarantorSearchResults; track client.id) {
{{ client.displayName }}
{{ client.accountNo ?? client.officeName ?? '' }}
}
}
}
Guarantor {{ i + 1 }} is not named yet. Search and select an existing bank client — a name alone isn't
enough.
}
}
@if (grantedApprovals(app).length) {
@for (ap of grantedApprovals(app); track ap.label) {
✓
{{ ap.label }} — {{ ap.approverName }} ({{ ap.role }}) ·
{{ ap.date }}
@if (ap.exception) {
On exception
}
@if (ap.remarks) {
}
}
}
@if (isStageApproved(a, field); as ap) {
@if (ap.remarks) {
}
@if (nextStageOf(a); as nxt) {
Proceed to Next Stage: {{ stageLabels[nxt] }}
}
} @else if (approvalRequest(a, field); as req) {
@if (isMyRequest(req)) {
@if (req.remarks) {
}
@if (req.checklist?.length && !(field === 'creditCommitteeApproval' && isDepositLoan(a))) {
@for (check of req.checklist; track check.label) {
{{ check.ok ? '✓' : '✕' }}
{{ check.label }}
}
}
You sent this request, so you cannot approve it. A different user has to approve, reject or revoke
it.
Withdraw request
} @else {
@if (req.previousRevokeRemarks) {
Re-submitted after correction
Previous reason for return: “{{ req.previousRevokeRemarks }}”
}
@if (req.checklist?.length && !(field === 'creditCommitteeApproval' && isDepositLoan(a))) {
@for (check of req.checklist; track check.label) {
{{ check.ok ? '✓' : '✕' }}
{{ check.label }}
}
@if (req.remarks) {
}
}
@if (autoChecked(a, field)) {
@for (item of checkerItems(a, field, req); track item.label) {
@if (!item.ok) {
✕
{{ item.label }} — this check has not passed, so it cannot be approved.
}
}
} @else {
@for (item of checkerItems(a, field, req); track item.label) {
@if (item.ok) {
{{ item.label }}
} @else {
✕
{{ item.label }} — the sender did not verify this, so it cannot be approved.
}
}
}
Approve
Revoke / Return for Correction
Reject
@if (!checkerReady(a, field, req) && !autoChecked(a, field)) {
Approve opens after you tick every row above. Revoke / Return is always available with remarks.
}
}
} @else {
@if (latestRevokedRequest(a, field); as revReq) {
@if (revReq.revokeRemarks || revReq.remarks) {
}
Please review the error note above, correct or re-upload the documents/data, and click
Re-submit for Approval below.
}
@if (latestRevokedRequest(a, field)) {
Re-submit for Approval
} @else {
Send for Approval
}
@if (exception) {
Send for Approval on Exception
}
}
@for (s of visibleStages(a); track s) {
@if (canJumpToStage(a, s)) {
{{ stepMarker(a, s) }}
{{ stageLabel(a, s) }}
} @else {
{{ stepMarker(a, s) }}
{{ stageLabel(a, s) }}
}
}
@if (a.overallStatus === 'REJECTED') {
Application Rejected — at {{ stageLabels[a.currentStage] }}
See the approval summary below for the recorded reason.
} @else if (a.overallStatus === 'ON_HOLD') {
Personal Discussion — {{ discrepancyLabels[a.discrepancyType] }}
} @else if (a.overallStatus === 'DISBURSED') {
Disbursed
Disbursement Date
{{ a.disbursementDate }}
Mode
{{ a.disbursementMode }}
@if (!isDepositLoan(a)) {
ACH Confirmation
{{ a.achConfirmationRef }}
}
@if (!isDepositLoan(a)) {
EMI Activation Confirmation
{{ a.emiActivationConfirmed ? 'Confirmed on ' + a.emiActivationDate : 'Pending' }}
}
Core Banking Loan Account
@if (a.fineractLoanAccountNo) {
A/C {{ a.fineractLoanAccountNo }}
@if (loanAccount) {
View Account
}
} @else if (loanAccount) {
A/C {{ loanAccount.accountNo }} · {{ loanAccount.status }}
View Account
} @else {
Mock disbursement only — no core banking account
}
EMI Repayment Schedule
@if (isRevolving(a)) {
{{ a.productName }} is a revolving/renewable limit — repaid on demand and renewed annually, not on a fixed
EMI schedule.
} @else {
Loan Amount
₹{{ a.requestedAmount | number: '1.0-0' }}
{{ a.tenureMonths }} months @ {{ a.interestRate }}%
Monthly EMI
₹{{ emiAmountFor(a) | number: '1.0-0' }}
Reducing balance
Total Interest Payable
₹{{ totalInterestFor(a) | number: '1.0-0' }}
over the full tenure
Total Amount Payable
₹{{ totalPayableFor(a) | number: '1.0-0' }}
principal + interest
}
} @else {
@if (loanAccount && a.currentStage !== 'CUSTOMER_SIGNING' && !showAccountCard(a)) {
Loan account {{ loanAccount.accountNo }}
{{
loanAccount.status
}}
View Account
}
@if (showAccountCard(a) && accountOverview; as ov) {
Loan account {{ loanAccount?.accountNo }}
{{
loanAccount?.status
}}
View Account
Account Details
@for (row of ov.account; track row.label) {
{{ row.label }}
{{ row.value }}
}
Approved By
Account approved by
{{ ov.approval.by }}
Approved on
{{ ov.approval.on }}
Approved amount
{{ ov.approval.amount }}
Approved Items
@for (row of approvedItems(a); track row.label) {
{{ row.label }}
{{ row.value }}
}
Added Items (charges)
@for (c of ov.charges; track c.name) {
{{ c.name }}
{{ c.amount }} · {{ c.when }}
{{
c.added ? 'Added' : 'Product'
}}
} @empty {
Charges
None
}
GL Accounts (from the product)
@for (row of ov.glAccounts; track row.label) {
{{ row.label }}
{{ row.value }}
}
@if (ov.posting) {
{{ ov.posting }}
}
@if (loanAccount?.active) {
✓ Disbursed. Completing the application…
} @else if (!loanAccountReady) {
The loan account has to be approved before it can be disbursed.
} @else if (a.currentStage !== 'DISBURSED') {
Disbursement can be sent for approval once the post-disbursement check is done.
} @else {
@switch (disbursementState(a)) {
@case ('NONE') {
Send for Disbursement Approval
}
@case ('MINE_PENDING') {
⏳ Sent for disbursement approval by you. Another user has to approve it; the loan is disbursed as
soon as they do.
Withdraw
}
@case ('OTHER_PENDING') {
Disbursement approval requested by {{ disbursementRequestedBy(a) }} . Debit {{ accountOverview?.glAccounts?.[1]?.value }}, credit
{{ accountOverview?.glAccounts?.[0]?.value }}.
Approve & Disburse
Decline
}
@case ('APPROVED') {
✓ Disbursement approved{{
a.disbursementApproval?.approverName ? ' by ' + a.disbursementApproval?.approverName : ''
}}.
{{ executingDisbursement ? 'Disbursing…' : 'Disbursing the loan…' }}
Disburse now
}
}
}
}
The purpose decides whether the loan counts as priority sector lending (RBI Master Directions, 2025) and
whether the borrower is a weaker section. It is needed before the sanction is approved.
Purpose of the loan
Priority sector
Product setting: {{ a.productName }} is
{{
isPrioritySectorProduct(a) ? 'a priority sector product' : 'not a priority sector product'
}} .
Is this loan priority sector?
Yes
No
@if (pslOverridden(a)) {
{{
pslChoice(a) === 'yes'
? 'Reason — priority sector although the product is not'
: 'Reason — not priority sector although the product is'
}}
}
@if (pslChoice(a) === 'yes') {
Priority sector category
Select
@for (category of prioritySectorCategories; track category) {
{{ category }}
}
@if (a.prioritySectorCategory) {
Document type
Select the document being uploaded
@for (type of pslDocTypes(a); track type) {
{{ type }}
}
@if (pslDocType && !pslLocked(a)) {
Upload — {{ pslDocType }}
}
@for (stored of pslDocs('PSL'); track stored.id) {
✓ {{ stored.description || stored.name }} — {{ stored.fileName }}
View
@if (!pslLocked(a)) {
Remove
}
}
}
}
Weaker section (overlapping tag, RBI para 17)
Does the borrower belong to a weaker section?
Select
Yes
No
@if (a.weakerSection === 'yes') {
Weaker section type
Select
@for (type of weakerSectionTypes; track type) {
{{ type }}
}
Document type
Select the document being uploaded
@for (type of weakerSectionDocumentTypes; track type) {
{{ type }}
}
@if (weakerDocType && !pslLocked(a)) {
Upload — {{ weakerDocType }}
}
@for (stored of pslDocs('WEAKER'); track stored.id) {
✓ {{ stored.description || stored.name }} — {{ stored.fileName }}
View
@if (!pslLocked(a)) {
Remove
}
}
}
@if (pslHint(a)) {
{{ pslHint(a) }}
} @else {
Purpose and priority sector classification complete
}
@if (showPslCard(a)) {
Purpose & Priority Sector
}
@if (a.currentStage === 'APPLICATION') {
Application Received
Received via
{{ a.channel === 'BC' ? a.bcAgentName : a.channel === 'SELF_APPLY' ? 'Self-Apply (Digital)' : 'Branch' }}
on {{ a.applicationDate }}.
Proceed to KYC & Document Collection
}
@if (a.currentStage === 'KYC_DOCUMENTS') {
KYC & Document Collection — OVD (RBI KYC Master Direction)
@if (isDepositLoan(a)) {
Loan against a deposit — the deposit is the security. Income proof, bank statement, address proof and a
co-borrower are optional , and no credit bureau (CIBIL) check is done. Only Aadhaar and PAN
verification are required.
}
@if (a.clientId) {
@if (loadingKyc) {
Loading KYC record…
} @else {
@if (realKyc?.aadhaarNumberMasked) {
{{ realKyc.aadhaarNumberMasked }}
}
@if (hasAadhaarPhotos()) {
} @else {
View Document
}
@if (realKyc?.panNumber) {
{{ maskPan(realKyc.panNumber) }}
}
@if (hasPanPhotos()) {
@if (hasPanFront() && hasPanBack()) {
@if (panFrontPreviewUrl || newKycCapture.pan.frontPreviewUrl) {
} @else {
}
Front
@if (panBackPreviewUrl || newKycCapture.pan.backPreviewUrl) {
} @else {
}
Back
} @else {
@if (
(hasPanFront() ? panFrontPreviewUrl : panBackPreviewUrl) ||
(hasPanFront() ? newKycCapture.pan.frontPreviewUrl : newKycCapture.pan.backPreviewUrl)
) {
} @else {
}
{{ hasPanFront() && !hasPanBack() ? 'PAN Card' : hasPanFront() ? 'Front' : 'Back' }}
}
} @else {
View Document
}
@if (findDocument('income'); as incomeDoc) {
{{ incomeDoc.name || incomeDoc.fileName }}
View Document
} @else {
Employment Type
Salaried
Business / Self-Employed
@if (newKycCapture.incomeProof.employmentType === 'SALARIED') {
@for (doc of newKycCapture.incomeProof.salaried; track $index) {
@if (doc.previewUrl) {
} @else {
View file
}
✕
}
@for (stored of storedDocsFor('KYC:incomeProof:salaried'); track stored.id) {
View file
✕
}
{{ salariedFileCount ? '+ Add More' : 'Upload Form 16 / Salary Slips' }}
{{ salariedFileCount }} file{{ salariedFileCount === 1 ? '' : 's' }} · Form 16 / Salary slips
} @else {
Last 3 years' Income Tax Returns:
@for (doc of newKycCapture.incomeProof.itr; track $index) {
@if (doc.exception) {
Exception Remark — Year {{ $index + 1 }}
}
}
}
}
@if (findDocument('bank statement'); as bankDoc) {
{{ bankDoc.name || bankDoc.fileName }}
View Document
} @else {
{{ newKycCapture.bankStatement.file ? 'Statement ✓' : 'Upload Bank Statement' }}
@if (newKycCapture.bankStatement.file || hasStoredDoc('KYC:bankStatement')) {
@if (newKycCapture.bankStatement.previewUrl) {
} @else {
View
}
@if (canReopenBankStatementAnalysis()) {
📊 Re-check Analysis
}
✕ Remove
}
}
@if (findDocument('electricity') || findDocument('address proof'); as billDoc) {
{{ billDoc.name || billDoc.fileName }}
View Document
} @else {
Bill Date
@if (electricityBillTooOld) {
Must not be older than 3 months.
}
}
}
} @else {
Captured for this application — final Aadhaar/PAN verification happens when the customer's CBS client
profile is created.
Aadhaar
{{ newKycCapture.aadhaar.front ? 'Front ✓' : 'Upload Front' }}
{{ newKycCapture.aadhaar.back ? 'Back ✓' : 'Upload Back' }}
@if (newKycCapture.aadhaar.front || newKycCapture.aadhaar.back) {
@if (newKycCapture.aadhaar.front) {
@if (newKycCapture.aadhaar.frontPreviewUrl) {
} @else {
Front file
}
}
@if (newKycCapture.aadhaar.back) {
@if (newKycCapture.aadhaar.backPreviewUrl) {
} @else {
Back file
}
}
}
@if (newKycCapture.aadhaar.verified) {
Aadhaar Verified
} @else {
}
PAN
{{ newKycCapture.pan.front ? 'Front ✓' : 'Upload Front' }}
{{ newKycCapture.pan.back ? 'Back ✓' : 'Upload Back' }}
@if (newKycCapture.pan.front || newKycCapture.pan.back) {
@if (newKycCapture.pan.front) {
@if (newKycCapture.pan.frontPreviewUrl) {
} @else {
Front file
}
}
@if (newKycCapture.pan.back) {
@if (newKycCapture.pan.backPreviewUrl) {
} @else {
Back file
}
}
}
@if (newKycCapture.pan.verified) {
PAN Verified
} @else {
Verify PAN
}
Income Proof
@if (isDepositLoan(a)) {
· optional
}
Employment Type
Salaried
Business / Self-Employed
@if (newKycCapture.incomeProof.employmentType === 'SALARIED') {
@for (doc of newKycCapture.incomeProof.salaried; track $index) {
@if (doc.previewUrl) {
} @else {
View file
}
✕
}
@for (stored of storedDocsFor('KYC:incomeProof:salaried'); track stored.id) {
View file
✕
}
{{ salariedFileCount ? '+ Add More' : 'Upload Form 16 / Salary Slips' }}
{{ salariedFileCount }} file{{ salariedFileCount === 1 ? '' : 's' }} · Form 16 and last 3 months'
salary slips — select several files at once.
} @else {
Last 3 years' Income Tax Returns:
@for (doc of newKycCapture.incomeProof.itr; track $index) {
@if (doc.exception) {
Exception Remark — Year {{ $index + 1 }}
}
}
}
@if (a.incomeProofSubmitted) {
@if (itrHasException) {
Submitted — with exception(s)
} @else {
Submitted
}
} @else {
Missing
}
Bank Statement
@if (isDepositLoan(a)) {
· optional
}
{{ newKycCapture.bankStatement.file ? 'Statement ✓' : 'Upload Bank Statement' }}
@if (newKycCapture.bankStatement.file) {
@if (newKycCapture.bankStatement.previewUrl) {
} @else {
View file
}
@if (isCsvFile(newKycCapture.bankStatement.file)) {
📊 Re-check Analysis
}
✕ Remove
}
@if (a.bankStatementSubmitted) {
Submitted
} @else {
Missing
}
Electricity Bill (Address Proof)
@if (isDepositLoan(a)) {
· optional
}
Bill Date
@if (electricityBillTooOld) {
Must not be older than 3 months.
}
@if (a.electricityBillSubmitted) {
Submitted
} @else {
Missing
}
}
@if (!!a.productDocuments) {
Loan-Specific Documents — {{ a.productName }}
@if (a.productDocuments.length === 0) {
{{ a.productName }} lists no required documents. Add any document the officer needs from the
customer.
}
@for (doc of a.productDocuments; track doc.key) {
@if (doc.key === 'coOwnerKyc') {
@if (doc.hint) {
{{ doc.hint }}
}
This property has a co-owner
@if (coOwnerCapture.hasCoOwner) {
{{ coOwnerCapture.aadhaar.verified ? 'Aadhaar ✓ Verified' : 'Verify Co-Owner Aadhaar' }}
{{ coOwnerCapture.pan.verified ? 'PAN ✓ Verified' : 'Verify Co-Owner PAN' }}
}
} @else {
@if (doc.hint) {
{{ doc.hint }}
}
}
}
+ Add Custom Document
}
@if (!isDepositLoan(a)) {
Monthly Income (₹)
@if (!isRevolving(a)) {
Requested Loan Amount (₹)
@if (amountOutOfRange(a)) {
{{ a.productName }} allows ₹{{ productLimitsFor(a)?.minAmt | number: '1.0-0' }} – ₹{{
productLimitsFor(a)?.maxAmt | number: '1.0-0'
}}
— this amount won't be saved until it's in range.
}
Tenure (Months)
@if (tenureOutOfRange(a)) {
{{ a.productName }} allows {{ productLimitsFor(a)?.minTenure }}–{{ productLimitsFor(a)?.maxTenure }}
months — this tenure won't be saved until it's in range.
}
}
Eligible Loan Amount preview: ₹{{ eligiblePreview(a) | number: '1.0-0' }}
@if (isRevolving(a)) {
{{ a.productName }} is a revolving/renewable limit — repaid on demand, no fixed EMI.
} @else {
Estimated EMI: ₹{{ emiPreview(a) | number: '1.0-0' }} / month ({{
emiToIncomePctPreview(a) | number: '1.0-1'
}}% of monthly income)
@if (emiToIncomePctPreview(a) > 40) {
@if (a.coBorrowerRequired && coBorrowerDetailsComplete(a) && combinedEligibilityOk(a)) {
EMI exceeds 40% of the applicant's own income, but the Co-Borrower added below already covers it —
see the Co-Borrower section.
} @else {
EMI exceeds 40% of monthly income — add a Co-Borrower, reduce the loan amount, or increase the
tenure before proceeding.
}
}
}
{{ a.monthlyIncome > 0 ? 'Update Income & Terms' : 'Assess Income & Calculate Eligible Amount' }}
@if (a.monthlyIncome > 0) {
Monthly Income (Last Assessed)
₹{{ a.monthlyIncome | number: '1.0-0' }}
Eligible Loan Amount
₹{{ a.eligibleLoanAmount | number: '1.0-0' }}
Estimated EMI
@if (isRevolving(a)) {
No fixed EMI (revolving limit)
} @else {
₹{{ emiAmountFor(a) | number: '1.0-0' }} / month
}
}
@if (!isRevolving(a)) {
EMI Calculation Basis
Principal (Loan Amount)
₹{{ a.requestedAmount | number: '1.0-0' }}
Interest Rate
{{ a.interestRate }}% p.a. ({{ a.interestRate / 12 | number: '1.2-2' }}% / month)
Tenure
{{ a.tenureMonths }} months
Total Interest Payable
₹{{ totalInterestFor(a) | number: '1.0-0' }}
Total Amount Payable
₹{{ totalPayableFor(a) | number: '1.0-0' }}
Reducing-balance EMI formula: EMI = [P × r × (1+r)n ] / [(1+r)n − 1] — where P
= Principal, r = Monthly Interest Rate, n = Tenure in months. On P = ₹{{
a.requestedAmount | number: '1.0-0'
}}, r = {{ a.interestRate / 12 / 100 | number: '1.4-4' }}, n = {{ a.tenureMonths }} → EMI = ₹{{
emiAmountFor(a) | number: '1.0-0'
}}
/ month.
}
@if (a.coBorrowerRequired || isDepositLoan(a)) {
Co-Borrower
@if (isDepositLoan(a)) {
(optional)
} @else {
(raises household eligibility)
}
Add a Co-Borrower to increase eligibility
@if (a.coBorrowerWanted) {
Co-Borrower Name
Relationship with Applicant
Select
Father
Mother
Wife
Husband
Son
Daughter
Other
Co-Borrower Monthly Income (₹)
Upload the co-borrower's last 3 months' salary slips:
@for (doc of coBorrowerCapture.salarySlips; track $index) {
{{
doc.file
? 'Salary Slip — Month ' + ($index + 1) + ' ✓'
: 'Upload Salary Slip — Month ' + ($index + 1)
}}
@if (doc.file || hasStoredDoc('COBORROWER:salarySlip:' + $index)) {
@if (doc.previewUrl) {
} @else {
View file
}
}
}
@if (coBorrowerDetailsComplete(a)) {
Combined Household Eligibility Calculation
Applicant's Monthly Income
₹{{ a.monthlyIncome | number: '1.0-0' }}
Applicant's EMI Capacity (40%)
₹{{ applicantEmiCapacity(a) | number: '1.0-0' }}
Co-Borrower's Monthly Income
₹{{ a.coBorrowerMonthlyIncome | number: '1.0-0' }}
Co-Borrower's EMI Capacity (40%)
₹{{ coBorrowerEmiCapacity(a) | number: '1.0-0' }}
Combined Household EMI Capacity
₹{{ combinedEmiCapacity(a) | number: '1.0-0' }}
Estimated EMI (this loan)
₹{{ emiAmountFor(a) | number: '1.0-0' }}
Combined Capacity = (40% × ₹{{ a.monthlyIncome | number: '1.0-0' }} applicant) + (40% × ₹{{
a.coBorrowerMonthlyIncome | number: '1.0-0'
}}
co-borrower) = ₹{{ applicantEmiCapacity(a) | number: '1.0-0' }} + ₹{{
coBorrowerEmiCapacity(a) | number: '1.0-0'
}}
= ₹{{ combinedEmiCapacity(a) | number: '1.0-0' }}. Estimated EMI ₹{{
emiAmountFor(a) | number: '1.0-0'
}}
is {{ combinedEligibilityOk(a) ? 'within' : 'above' }} this combined capacity.
@if (combinedEligibilityOk(a)) {
Eligible with Co-Borrower
} @else {
Still not eligible — increase co-borrower income, reduce the amount, or extend tenure
}
}
}
@if (!affordabilityOk(a)) {
@if (!coBorrowerDetailsComplete(a)) {
@if (!a.coBorrowerWanted) {
Check "Add a Co-Borrower" and complete their details to proceed.
} @else {
Add the co-borrower's name, relationship, monthly income and all 3 salary slips to proceed.
}
} @else {
Combined household income still doesn't cover the EMI at 40% — adjust the amount, tenure, or
co-borrower before proceeding.
}
}
}
}
@if (a.guarantorsRequiredCount !== undefined && guarantorsNeeded(a) > 0) {
}
Purpose & Priority Sector
{{ isDepositLoan(a) ? 'Complete KYC & Proceed' : 'Proceed to CIC / Credit Bureau Check' }}
}
@if (a.currentStage === 'CIC_CHECK') {
CIC / Credit Bureau Check — {{ a.cicBureau }}
Customer Consent — Credit Bureau Check
RBI's Fair Practices Code requires the customer's signed consent before a credit bureau pull. Generate
the declaration letter below, get it signed by the customer, then upload the signed copy.
@if (a.channel === 'BRANCH') {
Print Declaration Letter
} @else {
Download Declaration Letter
Share (Email / WhatsApp / Drive…)
Email
WhatsApp
}
{{ cicConsentCapture.file ? 'Signed Declaration ✓' : 'Upload Signed Declaration' }}
@if (cicConsentCapture.file || hasStoredDoc('CIC:consent')) {
@if (cicConsentCapture.previewUrl) {
} @else {
View file
}
}
@if (a.cicConsentSigned) {
Signed Declaration Uploaded
} @else {
Awaiting Signed Declaration
}
CIC Check Charge — ₹{{ cicCheckCharge }}
@if (a.clientId && realDebitableAccounts.length > 0) {
Select which account to debit the ₹{{ cicCheckCharge }} charge from:
@for (acc of realDebitableAccounts; track acc.id) {
{{ acc.kind }}
{{ acc.accountNo }} — {{ acc.productName }}
Balance: ₹{{ acc.accountBalance | number: '1.0-0' }}
}
} @else {
@if (a.clientId && loadingShareAccounts) {
Loading accounts…
} @else {
@if (a.clientId) {
No open savings/current account on file for this customer — collect the charge via payment link
instead.
}
@if (!a.cicPaymentLinkUrl || a.cicPaymentLinkUrl === '—') {
Generate Payment Link
} @else {
{{ a.cicPaymentLinkUrl }}
Copy Link
Email
WhatsApp
@if (!a.cicChargeCollected) {
Payment Reference No. (from customer)
Confirm Payment Received
}
}
}
}
@if (a.cicChargeCollected) {
Charge Collected —
{{ a.cicChargeMode === 'ACCOUNT_DEBIT' ? a.cicChargeAccountLabel : 'Ref ' + a.cicPaymentReference }}
} @else {
Charge Not Collected
}
@if (a.cibilScore === 0) {
Bureau
@for (bureau of cicBureaus; track bureau) {
{{ bureau }}
}
Check Credit Score
@if (!a.cicConsentSigned || !a.cicChargeCollected) {
Print/share the declaration and get it signed, and collect the ₹{{ cicCheckCharge }} check charge,
before checking the credit score.
}
} @else {
= 750"
[class.loi-cic-score-badge--good]="a.cibilScore >= 650 && a.cibilScore < 750"
[class.loi-cic-score-badge--fair]="a.cibilScore >= 550 && a.cibilScore < 650"
[class.loi-cic-score-badge--poor]="a.cibilScore < 550"
>
{{ a.cibilScore }}
{{ cibilBandOf(a.cibilScore) }}
Credit Bureau
{{ a.cicBureau }}
Uploaded Report File
{{
a.cicReportUploaded ? a.cicReportFileName : 'Not uploaded yet'
}}
Field Inquiry Status
{{
a.fiRequestPushed
? 'Pushed to ' + a.fiAgencyAssigned + ' (' + a.fiRequestDate + ')'
: 'Not pushed yet'
}}
@if (a.cicReportUploaded) {
📊 View Analysis
@if (hasStoredDoc('CIC:report')) {
View file
}
}
}
@if (a.cibilScore > 0) {
{{
a.cicReportUploaded ? '📄 Re-upload PDF Report' : 'Upload ' + a.cicBureau + ' Report (PDF)'
}}
@if (a.cicReportUploaded && !a.fiRequestPushed) {
Push Field Inquiry to Agency
} @else if (a.cicReportUploaded && a.fiRequestPushed) {
Proceed to Field Investigation
}
}
}
@if (a.currentStage === 'FIELD_INVESTIGATION') {
Field Investigation (FI) — Agent Report
@if (a.clientId) {
Registered Addresses on File (Fineract)
@if (loadingAddresses) {
Loading addresses…
} @else if (realAddresses.length === 0) {
No addresses on file for this client.
} @else {
@for (addr of realAddresses; track $index) {
{{ addr.addressType || 'Address' }}
{{ formatRealAddress(addr) }}
}
}
}
Applicant has a shop / business premises
@for (key of fiRows(a); track key) {
{{ fiCheckLabels[key] }}
@if (a[key].officerAssigned === '—') {
Assign Field Officer
Select an officer
@for (staffMember of fiStaffOptions; track staffMember.id) {
{{ staffMember.displayName }}
}
Assign Officer
} @else {
Assigned to {{ a[key].officerAssigned }} on {{ a[key].assignedDate }}
@if (a[key].status === 'PENDING') {
@if (fiIsOverdue(a, key)) {
⚠ {{ fiSlaLabel(a, key) }} — this visit is overdue.
} @else {
{{ fiSlaLabel(a, key) }}
}
Latitude
Longitude
Site Photos ({{ fiPhotoCapture[key].length }}):
Mark Verified — Address Correct
@if (!fiCanVerify(a, key)) {
Capture latitude, longitude and at least one site photo before marking Verified.
}
Reject — Remark (if address is incorrect)
Reject with Remark
} @else if (a[key].status === 'VERIFIED') {
Verified
📋 View Full Details
} @else {
Failed
📋 View Full Details
Re-Assign a New Field Officer
Select an officer
@for (staffMember of fiStaffOptions; track staffMember.id) {
{{ staffMember.displayName }}
}
Re-Assign Officer
}
}
}
@if (a.secured) {
}
Agent Report
{{ a.agentReportUploaded ? a.agentReportFileName : 'Not uploaded yet' }}
@if (a.agentReportUploaded) {
Report Remark
{{ a.agentReportRemark }}
}
@if (a.agentReportUploaded && hasStoredDoc('FI:agentReport')) {
View file
}
@if (!a.agentReportUploaded) {
Agent Report Reference / Remark
Upload Agent Report
}
Record FI & Proceed to Personal Discussion
}
@if (a.currentStage === 'PERSONAL_DISCUSSION' && isDepositLoan(a)) {
Personal Discussion with Manager — Loan Plan
@if (loanPlan(a); as plan) {
The plan below is what the customer is offered. Download or print it, share it with the customer, then
proceed.
Applicant {{ a.applicantName }}
Loan amount ₹{{ plan.amount | number: '1.0-0' }}
Tenure {{ plan.tenure }} months
Interest rate {{ plan.rate | number: '1.2-2' }}% p.a.
@if (plan.rateFromDeposit) {
(deposit {{ plan.depositRate }}% + {{ plan.spread }}%)
}
Interest per month (estimate) ₹{{ plan.monthlyInterest | number: '1.0-0' }}
Total interest over the tenure ₹{{ plan.totalInterest | number: '1.0-0' }}
Total payable at the end ₹{{ plan.totalPayable | number: '1.0-0' }}
Repayment {{ plan.repayment }}
Deposit pledged {{ plan.accounts }}
Security value · limit ₹{{ plan.securityValue | number: '1.0-0' }} · {{ plan.limitPct }}% = ₹{{
plan.eligible | number: '1.0-0'
}}
Lien {{ plan.lienRequired ? 'Marked ' + plan.lienStage : 'Not required' }}
Penal interest {{ plan.penal }}
Pre-closure · Renewal {{ plan.preclosure }} · {{ plan.renewal }}
What has been collected
@for (row of planCollectedRows(a); track row.label) {
{{ row.label }} {{ row.value }}
}
Product terms — {{ a.productName }}
@for (row of planProductRows(a); track row.label) {
{{ row.label }} {{ row.value }}
}
⬇️ Download Loan Plan (PDF)
🖨️ Print Loan Plan
Proceed to Sanction
}
}
@if (a.currentStage === 'PERSONAL_DISCUSSION' && !isDepositLoan(a)) {
Personal Discussion with Manager
Briefing Report — For the Meeting
Everything captured so far — KYC, CIC score, Field Investigation, property valuation, agent report and
the full stage history — as one PDF for whoever takes this meeting.
🖨️ Print Summary Report
⬇️ Download Summary Report
Meeting Scheduler
Meeting Date
Meeting Time
Mode of Meeting
Select
Offline (In-Branch)
Online (Video Call)
Phone Call
Bank Officer Taking the Meeting
Select
@for (m of meetingManagers; track m) {
{{ m }}
}
{{ a.meetingScheduled ? 'Update Schedule' : 'Schedule Meeting' }}
@if (a.meetingScheduled) {
Scheduled with {{ a.meetingWith }} on {{ a.meetingDate }} at {{ a.meetingTime }} ({{
a.meetingMode === 'ONLINE' ? 'Online' : a.meetingMode === 'CALL' ? 'Phone Call' : 'Offline'
}})
}
@if (a.meetingScheduled) {
Discrepancy (if any)
No Discrepancy
Document Discrepancy
Name Mismatch
Office Verification Failed
Property Discrepancy
FI Report Discrepancy
Fake Declaration Suspected
Discussion Report
@if (discrepancySelection === 'NONE') {
Clear, Take Declaration & Proceed to Loan Committee
} @else {
Flag Discrepancy — Hold Application
}
} @else {
Schedule the meeting above before recording the discussion report.
}
}
@if (a.currentStage === 'CREDIT_COMMITTEE') {
{{ isDepositLoan(a) ? 'Sanction' : 'Loan Committee Approval' }} — {{ sanctioningAuthorityOf(a) }}
@if (isDepositLoan(a)) {
Loan Application
The bank's loan application form, filled from this application: applicant particulars, occupation and
income, accounts and existing loans, the deposit offered as security and the declaration. After it
come the sanction checks and every document on file: the eKYC documents (Aadhaar, PAN), the lien
documents, the deposit documents and the legal documents.
🖨️ {{ loanApplicationBusy ? 'Preparing…' : 'Print Loan Application' }}
⬇️ {{ loanApplicationBusy ? 'Preparing…' : 'Download Loan Application' }}
} @else {
Full Application Report — For the Committee
Everything captured on this application — KYC, CIC score, Field Investigation, property valuation,
agent report, meeting and stage history — as one PDF for every committee member to review before
deciding.
🖨️ Print Full Report
⬇️ Download Full Report
}
@if (!isDepositLoan(a)) {
Reports Required — present below reports, then complete.
@if (!isDepositLoan(a)) {
CIBIL / Credit Bureau Report
}
Background Check{{
isDepositLoan(a) ? ' (optional)' : ''
}}
@if (a.secured) {
CSE — CERSAI Search Enquiry
}
OVD
@if (!isDepositLoan(a)) {
Income Proof
}
@if (!isDepositLoan(a)) {
FI Report
}
@if (!isDepositLoan(a)) {
Manager Meeting
}
Share Member Approval
@if (a.secured) {
0" disabled /> Property Valuation
}
}
@if (isDepositLoan(a)) {
@for (check of depositRiskChecks(a); track check.label) {
@if (!check.ok) {
{{ check.label }}
}
}
@if (guarantorsNeeded(a) > 0) {
}
}
Purpose & priority sector
Purpose of the loan
{{ a.loanPurpose || '—' }}
Priority sector
{{ pslChoice(a) === 'yes' ? 'Yes — ' + (a.prioritySectorCategory || 'category not chosen') : 'No' }}
Weaker section
{{
a.weakerSection === 'yes'
? 'Yes — ' + (a.weakerSectionType || 'type not chosen')
: a.weakerSection === 'no'
? 'No'
: '—'
}}
@if (pslHint(a)) {
{{ pslHint(a) }} Complete the "Purpose & Priority Sector" card at the top of this page.
}
@if (!approvalRequest(a, 'creditCommitteeApproval') && !isStageApproved(a, 'creditCommitteeApproval')) {
{{ isDepositLoan(a) ? 'Sanction Remarks' : 'Committee Remarks' }}
}
@if (!isDepositLoan(a)) {
Resolution No.
Resolution Date
@if (committeeReportsReady(a) && !committeeCanApprove(a)) {
Enter the Resolution No. and Resolution Date the committee passed this decision under before
approving.
}
}
@if (isDepositLoan(a)) {
Sanction letter
@if (isStageApproved(a, 'creditCommitteeApproval')) {
✓ Sanction approved — the sanction letter is released.
Download Sanction Letter (PDF)
Print Sanction Letter
} @else {
Prepare the loan application above and send it to the manager for sanction approval. The sanction
letter is released as soon as the manager approves.
}
}
}
@if (a.currentStage === 'RISK_APPROVAL') {
Risk Approval — Verification Checklist
}
@if (isDepositLoan(a)) {
@for (row of collectedDocs(a); track row.label) {
{{ row.label }}
@if (row.ok) {
✓ Collected
} @else {
Missing
}
{{ row.where }}
@for (stored of storedDocsFor(row.storeKey); track stored.id) {
View file
} @empty {
@if (row.ok) {
(marked received; no file attached)
}
}
@if (!approvalRequest(a, 'legalApproval')) {
{{ storedDocsFor(row.storeKey).length ? 'Update file' : '+ Add file' }}
}
}
}
@if (!isDepositLoan(a)) {
Processing Fee Collected
}
@if (a.secured) {
Mortgage Created
}
Legal Stamp Done
@if (!isDepositLoan(a)) {
File Filing Done
}
@if (a.legalDocuments.length > 0) {
@if (approvalRequest(a, 'legalApproval')) {
🔒 Sent for approval — the documents can be viewed but not added, replaced or removed. To change
anything, withdraw the request first.
}
@for (doc of a.legalDocuments; track doc.key) {
{{ legalDocIcon(doc.key) }}
{{ doc.label }}
@if (doc.submitted) {
✓ Submitted
@if (legalDocCapture[doc.key]?.length) {
· {{ legalDocCapture[doc.key].length }} file{{
legalDocCapture[doc.key].length > 1 ? 's' : ''
}}
this session
}
} @else {
Missing
}
@if (doc.custom && !approvalRequest(a, 'legalApproval')) {
✕
}
@for (capture of legalDocCapture[doc.key]; track $index) {
View file
@if (!approvalRequest(a, 'legalApproval')) {
✕
}
}
@for (stored of storedDocsFor('LEGAL_DOC:' + doc.key); track stored.id) {
View file
@if (!approvalRequest(a, 'legalApproval')) {
✕
}
}
@if (!approvalRequest(a, 'legalApproval')) {
+ Add File(s)
}
}
@if (!approvalRequest(a, 'legalApproval')) {
+ Add Custom Document
}
}
@if (a.currentStage === 'LEGAL_APPROVAL') {
Legal Approval — Fees & Legal Documents
}
@if (a.currentStage === 'CUSTOMER_SIGNING') {
Customer Signing Slot — {{ a.agreementSigningSlot }}
Loan Agreement and Sanction Letter ready for the customer's acknowledgement and signature.
@if (isDepositLoan(a)) {
Legal Documents
Agreement Signing Slot
@if (!legalChecklistDone(a)) {
Take the legal documents and the stamp duty before the customer signs.
}
}
@if (isDepositLoan(a)) {
Download Sanction Letter (PDF)
Print Sanction Letter
}
@if (!isCustomerSigned(a)) {
Mark Signed by Customer
} @else {
✓ Signed by Customer ({{ a.customerSigningDate }})
@if (hasLoanAccount(a)) {
Proceed to Next Stage ›
}
}
@if (isCustomerSigned(a)) {
@if (hasLoanAccount(a)) {
✓ Core Banking Loan Account Ready
{{ a.fineractLoanAccountNo || 'Linked' }}
} @else if (loanAccount) {
Loan Account Created
{{ loanAccount.status }}
} @else {
Customer Signed
Account Not Created
}
@if (hasLoanAccount(a)) {
Core Banking Loan Account ready: {{ a.fineractLoanAccountNo || 'Linked' }} . You can now proceed to the next stage.
} @else if (loanAccount) {
Loan account {{ loanAccount.accountNo }} is already created for this application
and is {{ loanAccount.status }} . A second account cannot be created.
@if (loanAccount.pendingApproval) {
Use Check Status to see when it is approved.
} @else if (loanAccountReady) {
You can now proceed to the next stage.
}
} @else {
Loan agreement signed for {{ a.productName }} (₹{{ a.requestedAmount | number: '1.0-0' }}).
Core Banking Loan Account not created yet for this application. Click below to
create the official loan account first.
}
@if (!hasLoanAccount(a)) {
Create Loan Account
{{ checkingLoanAccount ? 'Checking…' : '🔄 Check Status' }}
@if (loanAccount) {
View Account
@if (loanAccountReady) {
Proceed to Next Stage ›
}
}
} @else {
✓ Account: {{ a.fineractLoanAccountNo || 'Created' }}
Proceed to Next Stage ›
Unlink / Reset
}
}
}
@if (a.currentStage === 'CHEQUE_ACH') {
Cheque Received / ACH Sign
@if (isDepositLoan(a)) {
Not required for a loan against a deposit — the bank recovers by set-off against the lien.
} @else {
Cheque Received
ACH Mandate Signed
}
Confirm & Proceed to Post-Disbursement Check
}
@if (a.currentStage === 'POST_CHECK') {
Post-Disbursement Check — Final Compliance Gate
}
@if (a.currentStage === 'DISBURSED') {
Ready for Disbursement
Disbursement Mode
Account Credit
NEFT
RTGS
@if (!isDepositLoan(a)) {
Disbursing also confirms EMI Activation for this account in the same step.
}
@if (a.customerType === 'EXISTING' && a.clientId) {
A real Fineract loan account will be created, approved and disbursed in Core Banking at the same time.
} @else {
This is a mock disbursement only — no Core Banking account exists until this customer is fully onboarded
as a client.
}
@if (a.fineractLoanError) {
{{ a.fineractLoanError }}
}
@if (isDepositLoan(a)) {
@if (disbursementLienIssue(a); as issue) {
{{ issue }}
} @else {
✓ On disbursement the lien is marked on {{ a.depositSelection?.accountNos?.join(', ') }} for ₹{{
a.requestedAmount | number: '1.0-0'
}}.
}
}
@if (creatingRealLoan) {
Creating Real Loan Account in Core Banking…
} @else if (a.fineractLoanError) {
{{ isDepositLoan(a) ? 'Retry Disburse' : 'Retry Disburse & Confirm EMI Activation' }}
} @else {
{{ isDepositLoan(a) ? 'Disburse Now' : 'Disburse Now & Confirm EMI Activation' }}
}
}
}
@if (a.currentStage === 'DEPOSIT_SELECTION' && showLienCard(a)) {
1 · Select deposit
2 · Lien & Set-Off letter
@if (!a.depositSelection?.saved) {
Save the deposit first to open step 2.
}
}
@if (a.currentStage === 'DEPOSIT_SELECTION' && (!showLienCard(a) || depositStep === 1)) {
Deposit Selection & Eligibility
}
@if (showLienCard(a) && depositStep === 2) {
Deposits Under Lien
{{ a.depositSelection?.accountNos?.join(', ') || 'Select & save deposit above' }}
Lien Security Amount
₹{{ a.requestedAmount | number: '1.0-0' }}
@if (!canMakeLienLetter(a)) {
Select and save a deposit above to generate the Letter of Lien and Set-off.
}
@if (lienLetterStored) {
Signed Letter of Lien & Set-Off
✓ Received
@for (stored of storedDocsFor('LIEN:letter'); track stored.id) {
}
} @else {
}
@if (a.lien?.marked && depositRules(a).certificateRequired) {
LIEN CERTIFICATE
No: {{ a.lien?.certificateNo }}
Date: {{ a.lien?.markedOn }}
A lien of ₹{{ a.lien?.amount | number: '1.0-0' }} is noted on deposit
{{ a.lien?.accountNos?.join(', ') }} in favour of the bank against loan application
{{ a.applicationNo }}.
} @else if (lienAtDisbursement(a)) {
Automated Lien at Disbursement
This product marks the lien at disbursement . The lien is placed on the deposit automatically when
the loan is disbursed, so there is nothing to mark now. Before that: save the deposit selection and
upload the signed letter of lien and set-off above.
} @else {
Mark Lien
@if (!lienReady(a)) {
Save the deposit selection and upload the letter of lien and set-off to enable Mark Lien.
}
}
}
@if (a.currentStage === 'DEPOSIT_SELECTION' && (!showLienCard(a) || depositStep === 2)) {
Complete Deposit Selection
Order: choose the deposit and save it, then download the letter of lien and set-off, get it signed, and
upload it. Then proceed.
@if (depositStageIssue(a); as issue) {
{{ issue }}
} @else {
✓ Deposit saved and the signed letter is on file. Ready to proceed.
}
Complete Deposit Selection & Proceed
}
Approvals & Application Journey
{{ a.stageHistory.length }} recorded audit trail events · 4 sanctioning approval checkpoints.
View Approval Matrix
Open Journey Timeline
Approval Matrix ({{ approvalTilesFor(a).length }})
Journey Timeline ({{ a.stageHistory.length }})
@if (activeDrawerTab === 'approvals') {
@for (tile of approvalTilesFor(a); track tile.field) {
@if (approvalOf(a, tile.field); as ap) {
{{ tile.label }}
@if (approvalRequestAny(a, tile.field); as req) {
@if (req.status === 'PENDING') {
⏳ AWAITING APPROVAL
Sent by {{ req.submittedBy }} · {{ req.submittedOn }}
@if (req.requestedDecision === 'EXCEPTION_APPROVED') {
On exception
}
@if (req.remarks) {
“{{ req.remarks }}”
}
} @else if (req.status === 'WITHDRAWN') {
WITHDRAWN
Sent by {{ req.submittedBy }} · {{ req.submittedOn }}, then withdrawn
} @else if (req.status === 'REVOKED') {
RETURNED FOR RECTIFICATION
Returned by {{ req.decidedBy || 'Approver' }} · {{ req.decidedOn }}
@if (req.revokeRemarks || req.remarks) {
“{{ req.revokeRemarks || req.remarks }}”
}
} @else {
{{ ap.decision }}
Sent by {{ req.submittedBy }} · {{ req.submittedOn }}
{{ ap.decision === 'REJECTED' ? 'Rejected' : 'Approved' }} by {{ ap.approverName }} ·
{{ ap.date }}
@if (req.checkerChecklist?.length) {
Checker verified {{ checkerSummary(req) }}
}
{{ ap.remarks }}
}
} @else {
{{ ap.decision }}
@if (ap.decision === 'PENDING') {
Not sent for approval yet
} @else {
{{ ap.approverName }} · {{ ap.date }}
{{ ap.remarks }}
}
}
}
}
}
@if (activeDrawerTab === 'journey') {
@for (h of a.stageHistory; track h.date + h.stage + h.outcome) {
{{ stepMarker(a, h.stage) }}
{{ stageLabels[h.stage] }} — {{ h.outcome }}
{{ h.date }}
{{ h.actionBy }}
} @empty {
No activity recorded yet.
}
}
} @else {
Application Not Found
‹ Back to Pipeline
}