Skip to main content

GetLoanQuoteDocumentsQuery

Overview

The GetLoanQuoteDocumentsQuery retrieves a list of all documents associated with a loan application. This query is optimized for performance by returning only document metadata without the actual file content, making it ideal for displaying document lists in the UI.

Handler File: CB.Administration.Api/Commands/BPM/SelfService/DocumentManagementCommand.cs

Use Cases

  • Display list of uploaded documents in loan application UI
  • Show document checklist with completion status
  • Audit trail of all documents submitted
  • Quick overview of available documentation
  • Document management dashboard

Performance Optimization

🚀 Fast Query: This query excludes the documentData field, making responses 500x smaller and faster than including full document content.

Example:

  • 50 documents with data: ~25MB response, 5-10 seconds
  • 50 documents without data: ~50KB response, 100-200ms ⚡

Request Parameters

Required Parameters

ParameterTypeDescription
loanQuoteIdlongThe ID of the loan quote to retrieve documents for

Request Example

{
"cmd": "GetLoanQuoteDocumentsQuery",
"data": {
"loanQuoteId": 110
}
}

Response Format

Success Response

{
"statusCode": "00",
"statusMessage": "SUCCESS",
"data": [
{
"documentId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"documentName": "National ID Card.pdf",
"documentType": 1,
"documentTypeName": "NATIONAL_ID",
"description": "Customer national ID card - front and back",
"documentNumber": "ABC123456",
"documentExpiry": "2030-12-31T00:00:00Z",
"documentIssueDate": "2020-01-15T00:00:00Z",
"documentIssuer": "National Identity Management Commission",
"createdDate": "2026-01-10T14:30:00Z",
"createdBy": {
"userId": 25,
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@bank.com"
}
},
{
"documentId": "b2c3d4e5-f6g7-8901-bcde-f12345678901",
"documentName": "Bank Statement - December 2025.pdf",
"documentType": 5,
"documentTypeName": "BANK_STATEMENT",
"description": "Last 3 months bank statement",
"documentNumber": null,
"documentExpiry": null,
"documentIssueDate": "2026-01-05T00:00:00Z",
"documentIssuer": "Customer Bank",
"createdDate": "2026-01-11T09:15:00Z",
"createdBy": {
"userId": 25,
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@bank.com"
}
}
]
}

Empty Result Response

{
"statusCode": "00",
"statusMessage": "SUCCESS",
"data": []
}

Error Response

{
"statusCode": "01",
"statusMessage": "Loan quote with ID 999 not found",
"data": null
}

Response Fields

FieldTypeDescription
documentIdstring (GUID)Unique identifier for the document
documentNamestringFile name
documentTypeintDocument type enum value
documentTypeNamestringHuman-readable type name
descriptionstringDocument description
documentNumberstringOfficial document number
documentExpiryDateTimeExpiration date (if applicable)
documentIssueDateDateTimeIssue date
documentIssuerstringIssuing organization
createdDateDateTimeUpload timestamp
createdByobjectUser who uploaded the document

⚠️ Note: The documentData field is NOT included in this response for performance reasons.

JavaScript Usage Example

// Fetch and display document list
const loadDocumentList = async (loanQuoteId) => {
try {
const result = await api.query({
cmd: "GetLoanQuoteDocumentsQuery",
data: JSON.stringify({ loanQuoteId })
});

if (result.statusCode === "00") {
const documents = result.data;
console.log(`Found ${documents.length} documents`);

// Display in UI
displayDocuments(documents);

return documents;
} else {
console.error("Error:", result.statusMessage);
return [];
}
} catch (error) {
console.error("Failed to load documents:", error);
return [];
}
};

// Display documents in table
const displayDocuments = (documents) => {
const tbody = document.querySelector('#documentTable tbody');
tbody.innerHTML = '';

documents.forEach(doc => {
const row = tbody.insertRow();

row.innerHTML = `
<td>${doc.documentName}</td>
<td>${doc.documentTypeName}</td>
<td>${doc.documentNumber || 'N/A'}</td>
<td>${new Date(doc.createdDate).toLocaleDateString()}</td>
<td>${doc.createdBy.firstName} ${doc.createdBy.lastName}</td>
<td>
<button onclick="downloadDocument('${doc.documentId}')">
Download
</button>
</td>
`;
});
};

// Download specific document (use GetLoanQuoteDocumentByIdQuery)
const downloadDocument = async (documentId) => {
// See get-loan-quote-document-by-id.md for download implementation
console.log("Downloading document:", documentId);
};

Complete UI Component Example

class LoanDocumentViewer {
constructor(loanQuoteId, containerId) {
this.loanQuoteId = loanQuoteId;
this.container = document.getElementById(containerId);
this.documents = [];
}

async load() {
const result = await api.query({
cmd: "GetLoanQuoteDocumentsQuery",
data: JSON.stringify({ loanQuoteId: this.loanQuoteId })
});

if (result.statusCode === "00") {
this.documents = result.data;
this.render();
}
}

render() {
const html = `
<div class="document-list">
<h3>Loan Documents (${this.documents.length})</h3>
<table class="table">
<thead>
<tr>
<th>Document Name</th>
<th>Type</th>
<th>Upload Date</th>
<th>Uploaded By</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
${this.documents.map(doc => this.renderRow(doc)).join('')}
</tbody>
</table>
</div>
`;

this.container.innerHTML = html;
}

renderRow(doc) {
const uploadDate = new Date(doc.createdDate).toLocaleDateString();
const uploadedBy = `${doc.createdBy.firstName} ${doc.createdBy.lastName}`;

return `
<tr>
<td>
<i class="file-icon"></i> ${doc.documentName}
</td>
<td>
<span class="badge">${doc.documentTypeName}</span>
</td>
<td>${uploadDate}</td>
<td>${uploadedBy}</td>
<td>
<button class="btn-download"
onclick="viewer.download('${doc.documentId}')">
Download
</button>
</td>
</tr>
`;
}

async download(documentId) {
// Use GetLoanQuoteDocumentByIdQuery to download
const result = await api.query({
cmd: "GetLoanQuoteDocumentByIdQuery",
data: JSON.stringify({
loanQuoteId: this.loanQuoteId,
documentId: documentId
})
});

if (result.statusCode === "00") {
const doc = result.data;
const blob = this.base64ToBlob(doc.documentData);
const url = URL.createObjectURL(blob);

const a = document.createElement('a');
a.href = url;
a.download = doc.documentName;
a.click();

URL.revokeObjectURL(url);
}
}

base64ToBlob(base64) {
const byteCharacters = atob(base64);
const byteNumbers = new Array(byteCharacters.length);

for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}

const byteArray = new Uint8Array(byteNumbers);
return new Blob([byteArray]);
}
}

// Usage
const viewer = new LoanDocumentViewer(110, 'documentContainer');
viewer.load();

Document Type Reference

ValueNameCommon Use
1NATIONAL_IDPrimary identification
2INTERNATIONAL_PASSPORTInternational ID
3DRIVERS_LICENCEAlternate ID
4UTILITY_BILLAddress verification
5BANK_STATEMENTFinancial verification
6COMPANY_REGISTRATIONBusiness verification
7TAX_CLEARANCETax compliance

Error Codes

Status CodeDescription
00Success - documents retrieved
01Loan quote not found
99General error (see statusMessage)

Performance Tips

DO: Use this query for displaying document lists
DO: Cache the list and refresh only when needed
DO: Use pagination if dealing with 100+ documents

DON'T: Use this for downloading documents (use GetLoanQuoteDocumentByIdQuery)
DON'T: Poll this endpoint repeatedly (use webhooks/SignalR for updates)

Database Query

-- Simplified version of what the handler executes
SELECT
d.DocumentId,
d.DocumentName,
d.DocumentType,
d.Description,
d.DocumentNumber,
d.DocumentExpiry,
d.DocumentIssueDate,
d.DocumentIssuer,
d.CreatedDate,
-- DocumentData is NOT selected (performance!)
u.Id AS UserId,
ud.FirstName,
ud.LastName,
ud.Email
FROM [BPMSelfServiceDocument].[dbo].[SelfServiceDocumentAssociation] da
INNER JOIN [BPMSelfServiceDocument].[dbo].[SelfServiceDocument] d
ON da.SelfServiceDocumentId = d.Id
LEFT JOIN [Administration].[dbo].[SelfServiceUser] u
ON d.CreatedByUserId = u.Id
LEFT JOIN [Administration].[dbo].[UserDetail] ud
ON u.UserDetailId = ud.Id
WHERE da.AssociatedLoanId = @loanQuoteId
ORDER BY d.CreatedDate DESC

Testing Checklist

  • Retrieve documents for loan with 0 documents
  • Retrieve documents for loan with 1 document
  • Retrieve documents for loan with 10+ documents
  • Verify documentData field is NOT in response
  • Test with invalid loanQuoteId
  • Verify response time (less than 200ms for 50 docs)
  • Check creator information is included
  • Verify all metadata fields are populated