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
| Parameter | Type | Description |
|---|---|---|
loanQuoteId | long | The 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
| Field | Type | Description |
|---|---|---|
documentId | string (GUID) | Unique identifier for the document |
documentName | string | File name |
documentType | int | Document type enum value |
documentTypeName | string | Human-readable type name |
description | string | Document description |
documentNumber | string | Official document number |
documentExpiry | DateTime | Expiration date (if applicable) |
documentIssueDate | DateTime | Issue date |
documentIssuer | string | Issuing organization |
createdDate | DateTime | Upload timestamp |
createdBy | object | User 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
| Value | Name | Common Use |
|---|---|---|
| 1 | NATIONAL_ID | Primary identification |
| 2 | INTERNATIONAL_PASSPORT | International ID |
| 3 | DRIVERS_LICENCE | Alternate ID |
| 4 | UTILITY_BILL | Address verification |
| 5 | BANK_STATEMENT | Financial verification |
| 6 | COMPANY_REGISTRATION | Business verification |
| 7 | TAX_CLEARANCE | Tax compliance |
Error Codes
| Status Code | Description |
|---|---|
| 00 | Success - documents retrieved |
| 01 | Loan quote not found |
| 99 | General error (see statusMessage) |
Related Commands
- CreateLoanQuoteDocumentCommand - Upload new document
- GetLoanQuoteDocumentByIdQuery - Download specific document
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