feat: add KYC document renewal alerts, Aadhaar/PAN exceptions, and AML recurring alerts UI; remove old journal AML marking
build-run / Run Lint, Build and Deploy (push) Canceled after 0s
Publish Image in Docker Hub / build (push) Canceled after 0s
Playwright E2E Tests / Run Playwright Tests (push) Canceled after 0s
Tests / testRigor (push) Canceled after 0s

This commit is contained in:
2026-08-11 11:11:18 +05:30
parent 01e86173c1
commit 7b895a0e2b
77 changed files with 10046 additions and 1130 deletions
+111
View File
@@ -93,6 +93,117 @@ describe('deriveKycExceptionFields', () => {
});
});
describe('PAN declaration', () => {
it('waives the PAN exception once a declaration is taken', () => {
// The client's name/DOB will never match the PAN record, so the API can never pass. The
// signed declaration closes the item instead — the client must not sit in the exception list.
expect(
deriveKycExceptionFields({
...newIndividual(false, true),
panDeclarationTaken: true
})
).toEqual({
isException: false,
exceptionReason: null,
exceptionResolved: false,
exceptionResolvedOn: null
});
});
it('still raises the PAN exception when no declaration has been taken', () => {
expect(
deriveKycExceptionFields({
...newIndividual(false, true),
panDeclarationTaken: false
}).exceptionReason
).toBe(KYC_EXCEPTION_PAN);
});
it('leaves an outstanding Aadhaar untouched — a PAN declaration covers PAN only', () => {
const result = deriveKycExceptionFields({
...newIndividual(false, false),
panDeclarationTaken: true
});
expect(result.isException).toBe(true);
expect(result.exceptionReason).toBe(KYC_EXCEPTION_AADHAAR);
});
it('closes an existing PAN exception when a declaration is taken afterwards', () => {
expect(
deriveKycExceptionFields({
...existingException(false, true, KYC_EXCEPTION_PAN),
panDeclarationTaken: true
})
).toEqual({
isException: false,
exceptionReason: KYC_EXCEPTION_PAN,
exceptionResolved: true,
exceptionResolvedOn: TODAY
});
});
});
describe('Aadhaar enrolment receipt', () => {
it('waives the Aadhaar exception once the enrolment receipt is recorded', () => {
// The client holds no Aadhaar yet, so there is no number to run the OTP check against. The
// UIDAI enrolment slip closes the item instead.
expect(
deriveKycExceptionFields({
...newIndividual(true, false),
aadhaarReceiptTaken: true
})
).toEqual({
isException: false,
exceptionReason: null,
exceptionResolved: false,
exceptionResolvedOn: null
});
});
it('still raises the Aadhaar exception when no receipt has been taken', () => {
expect(
deriveKycExceptionFields({
...newIndividual(true, false),
aadhaarReceiptTaken: false
}).exceptionReason
).toBe(KYC_EXCEPTION_AADHAAR);
});
it('leaves an outstanding PAN untouched — a receipt covers Aadhaar only', () => {
const result = deriveKycExceptionFields({
...newIndividual(false, false),
aadhaarReceiptTaken: true
});
expect(result.isException).toBe(true);
expect(result.exceptionReason).toBe(KYC_EXCEPTION_PAN);
});
it('closes an existing Aadhaar exception when a receipt is taken afterwards', () => {
expect(
deriveKycExceptionFields({
...existingException(true, false, KYC_EXCEPTION_AADHAAR),
aadhaarReceiptTaken: true
})
).toEqual({
isException: false,
exceptionReason: KYC_EXCEPTION_AADHAAR,
exceptionResolved: true,
exceptionResolvedOn: TODAY
});
});
it('clears both items when a PAN declaration and an Aadhaar receipt are both on file', () => {
// Neither check can pass, yet the branch holds paperwork for both — nothing is outstanding.
const result = deriveKycExceptionFields({
...newIndividual(false, false),
panDeclarationTaken: true,
aadhaarReceiptTaken: true
});
expect(result.isException).toBe(false);
expect(result.exceptionReason).toBeNull();
});
});
describe('resolving', () => {
it('closes the exception once both checks pass, keeping the reason for the audit trail', () => {
const both = `${KYC_EXCEPTION_PAN}, ${KYC_EXCEPTION_AADHAAR}`;