fix(abdm-m1): user friendly OTP errors, remove bridge request id from UI, and add beneficiary name consent collection
This commit is contained in:
parent
763af46de2
commit
6bd24303e3
|
|
@ -25,6 +25,7 @@ class Abha extends BaseController
|
|||
$aadhaar = preg_replace('/\D/', '', trim((string) ($this->request->getPost('aadhaar') ?? '')));
|
||||
$authType = trim((string) ($this->request->getPost('auth_type') ?? 'aadhaar_otp'));
|
||||
$consent = $this->request->getPost('consent');
|
||||
$beneficiaryName = trim((string) ($this->request->getPost('beneficiary_name') ?? ''));
|
||||
|
||||
if (strlen($aadhaar) !== 12 || ! $this->validateVerhoeff($aadhaar)) {
|
||||
return $this->response->setJSON(['ok' => 0, 'error_text' => 'Aadhaar Number is not valid. Valid 12-digit Aadhaar number is required.']);
|
||||
|
|
@ -47,6 +48,9 @@ class Abha extends BaseController
|
|||
// later for local-patient name/age/gender/aadhaar matching (never sent to browser).
|
||||
if ($txnId) {
|
||||
session()->set('abha_aadhaar_txn_' . $txnId, $aadhaar);
|
||||
if ($beneficiaryName !== '') {
|
||||
session()->set('abha_beneficiary_' . $txnId, $beneficiaryName);
|
||||
}
|
||||
}
|
||||
return $this->response->setJSON([
|
||||
'ok' => 1,
|
||||
|
|
@ -102,10 +106,7 @@ class Abha extends BaseController
|
|||
|
||||
if (empty($result['ok']) || $result['ok'] != 1) {
|
||||
$requestId = trim((string) ($result['request_id'] ?? ''));
|
||||
$errorText = $this->extractBridgeErrorText($result, 'Please enter a valid OTP. Entered OTP is either expired or incorrect.');
|
||||
if ($requestId !== '') {
|
||||
$errorText .= ' (Bridge Request ID: ' . $requestId . ')';
|
||||
}
|
||||
$errorText = $this->extractBridgeErrorText($result, 'Incorrect OTP');
|
||||
return $this->response->setJSON([
|
||||
'ok' => 0,
|
||||
'error_text' => $errorText,
|
||||
|
|
@ -1669,7 +1670,22 @@ class Abha extends BaseController
|
|||
if (stripos($trimmed, 'loginId') !== false && stripos($trimmed, 'invalid') !== false) {
|
||||
return 'Aadhaar Number is not valid. Valid 12-digit Aadhaar number is required.';
|
||||
}
|
||||
return $trimmed;
|
||||
// Normalize ABDM/UIDAI OTP errors: replace technical error codes with clear user-friendly messages (ABDM M1)
|
||||
if (preg_match('/(?:UIDAI Error code\s*:\s*403|attempts for OTP match is exceeded|max(?:imum)? number of attempts.*exceeded)/i', $trimmed)) {
|
||||
return 'Incorrect OTP. Maximum number of attempts exceeded. Please generate a fresh OTP and try again.';
|
||||
}
|
||||
if (preg_match('/(?:UIDAI Error code\s*:\s*400|Invalid (?:Aadhaar )?OTP value|Invalid OTP|Incorrect OTP|OTP mismatch|OTP.*not valid|OTP.*either expired or incorrect)/i', $trimmed)) {
|
||||
return 'Incorrect OTP';
|
||||
}
|
||||
// Strip raw technical error code prefixes (e.g. ABDM-1204 : or UIDAI Error code : 400 :)
|
||||
$cleaned = preg_replace('/^(?:ABDM-\d+\s*:\s*)?(?:UIDAI Error code\s*:\s*\d+\s*:\s*)?/i', '', $trimmed);
|
||||
if (preg_match('/(?:invalid.*otp|incorrect.*otp|otp.*invalid|otp.*incorrect|otp.*match)/i', $cleaned)) {
|
||||
if (preg_match('/(?:attempts|exceeded|403)/i', $cleaned)) {
|
||||
return 'Incorrect OTP. Maximum number of attempts exceeded. Please generate a fresh OTP and try again.';
|
||||
}
|
||||
return 'Incorrect OTP';
|
||||
}
|
||||
return $cleaned;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1691,6 +1707,10 @@ class Abha extends BaseController
|
|||
$fieldMsg = trim($message);
|
||||
if (strcasecmp($field, 'loginId') === 0 && stripos($fieldMsg, 'invalid') !== false) {
|
||||
$fieldErrors[] = 'Aadhaar Number is not valid. Valid 12-digit Aadhaar number is required.';
|
||||
} elseif (preg_match('/(?:attempts.*exceeded|403)/i', $fieldMsg)) {
|
||||
$fieldErrors[] = 'Incorrect OTP. Maximum number of attempts exceeded. Please generate a fresh OTP and try again.';
|
||||
} elseif (preg_match('/(?:invalid.*otp|incorrect.*otp|otp.*match)/i', $fieldMsg)) {
|
||||
$fieldErrors[] = 'Incorrect OTP';
|
||||
} else {
|
||||
$fieldErrors[] = $field . ': ' . $fieldMsg;
|
||||
}
|
||||
|
|
@ -1700,6 +1720,10 @@ class Abha extends BaseController
|
|||
return implode('; ', $fieldErrors);
|
||||
}
|
||||
|
||||
if (preg_match('/(?:invalid.*otp|incorrect.*otp|otp.*expired)/i', $fallback)) {
|
||||
return 'Incorrect OTP';
|
||||
}
|
||||
|
||||
return $fallback;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -844,10 +844,22 @@
|
|||
|
||||
for (var i = 0; i < candidates.length; i++) {
|
||||
if (typeof candidates[i] === 'string' && candidates[i].trim() !== '') {
|
||||
return candidates[i].trim();
|
||||
var val = candidates[i].trim();
|
||||
if (/UIDAI Error code/i.test(val) || /ABDM-1204/i.test(val) || /attempts.*exceeded/i.test(val) || /invalid.*otp/i.test(val) || /incorrect.*otp/i.test(val) || /otp.*match/i.test(val) || /otp.*expired/i.test(val)) {
|
||||
if (/attempts.*exceeded/i.test(val) || /403/.test(val)) {
|
||||
return 'Incorrect OTP. Maximum number of attempts exceeded. Please generate a fresh OTP and try again.';
|
||||
}
|
||||
return 'Incorrect OTP';
|
||||
}
|
||||
val = val.replace(/\s*\(Bridge Request ID:[^)]*\)/gi, '').replace(/^ABDM-\d+\s*:\s*/i, '');
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
if (/invalid.*otp|incorrect.*otp/i.test(fallbackText)) {
|
||||
return 'Incorrect OTP';
|
||||
}
|
||||
|
||||
return fallbackText;
|
||||
}
|
||||
|
||||
|
|
@ -1439,7 +1451,7 @@
|
|||
window.AbhaPatientMatchModal.open(profile, profile.candidates || [], function(finalResponse) {
|
||||
if (typeof showRegResult === 'function') showRegResult(finalResponse);
|
||||
});
|
||||
}, $('#input_mphone1').val());
|
||||
}, $('#input_mphone1').val(), $('#input_name').val());
|
||||
}).on('click.abhaLauncher', '#abha_open_verify_modal_btn', function() {
|
||||
openAbhaAccountVerification('', null);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -563,7 +563,7 @@ $(document).ready(function() {
|
|||
});
|
||||
}
|
||||
window.AbhaPatientMatchModal.open(profile, candidates, refreshProfile, currentPatientId);
|
||||
}, <?= json_encode((string) ($data[0]->mphone1 ?? '')) ?>);
|
||||
}, <?= json_encode((string) ($data[0]->mphone1 ?? '')) ?>, <?= json_encode(trim((string) ($data[0]->p_fname ?? ''))) ?>);
|
||||
});
|
||||
|
||||
function getPatientIdOrWarn() {
|
||||
|
|
|
|||
|
|
@ -10,8 +10,33 @@
|
|||
* Step 5: ABHA Profile, Official Card & HIMS linking (CRT_ABHA_113, 114, 115 / TAGGING_UNIQUEPATIENTID_UNIQUEABHANUMBER)
|
||||
*
|
||||
* Include once per page: <?= view('partials/abha_create_modal') ?>
|
||||
* Then call: window.AbhaCreateModal.open(function (profile) { ... }, prefillMobile);
|
||||
* Then call: window.AbhaCreateModal.open(function (profile) { ... }, prefillMobile, prefillName);
|
||||
*/
|
||||
$healthcareWorkerName = 'Healthcare Worker';
|
||||
if (function_exists('auth') && auth()->loggedIn()) {
|
||||
$u = auth()->user();
|
||||
$healthcareWorkerName = $u->username ?? 'Healthcare Worker';
|
||||
if ($u && !empty($u->id)) {
|
||||
try {
|
||||
$db = \Config\Database::connect();
|
||||
$tables = config('Auth')->tables ?? [];
|
||||
$identitiesTable = $tables['identities'] ?? 'auth_identities';
|
||||
if ($db && $db->tableExists($identitiesTable)) {
|
||||
$row = $db->table($identitiesTable)
|
||||
->where('user_id', $u->id)
|
||||
->where('type', 'email_password')
|
||||
->get()
|
||||
->getRowArray();
|
||||
if (!empty($row['extra'])) {
|
||||
$extra = json_decode($row['extra'], true);
|
||||
if (!empty($extra['full_name'])) {
|
||||
$healthcareWorkerName = trim($extra['full_name']);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<style>
|
||||
.abha-create-modal .modal-content { border:0; border-radius:12px; overflow:hidden; }
|
||||
|
|
@ -28,6 +53,8 @@
|
|||
.abha-create-consent.border-danger { border-color:#dc3545 !important; border-style:solid !important; }
|
||||
#abhaCreateConsentAgreeWrap { transition: all .15s ease-in-out; }
|
||||
#abhaCreateConsentAgreeWrap.border-danger { border-color:#dc3545 !important; background-color:#fff5f5 !important; }
|
||||
.abha-declaration-card { background:#fbfcfe; border:1px solid #dce3ec; border-radius:8px; padding:10px 14px; margin-top:10px; transition:border-color .15s ease-in-out, background-color .15s ease-in-out; }
|
||||
.abha-declaration-card.border-danger { border-color:#dc3545 !important; background-color:#fff5f5 !important; }
|
||||
.abha-create-address { display:block; border:1px solid #dce3ec; border-radius:8px; padding:11px 14px; cursor:pointer; font-family:ui-monospace,SFMono-Regular,Menlo,monospace; }
|
||||
.abha-create-address:has(input:checked) { border-color:#356cf4; background:#edf2ff; box-shadow:0 0 0 1px #356cf4; }
|
||||
.abha-profile-list { margin:0; }
|
||||
|
|
@ -128,8 +155,25 @@
|
|||
I Agree — I have read and agree to all consent declarations for Aadhaar authentication and ABHA creation <span class="text-danger">*</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- ABDM M1 Declarations: Healthcare Worker & Beneficiary Name (Image 3) -->
|
||||
<div class="abha-declaration-card" id="abhaCreateDeclarationWrap">
|
||||
<div class="form-check d-flex align-items-start" id="abhaCreateHcwConsentWrap">
|
||||
<input class="form-check-input me-2 mt-1 flex-shrink-0" type="checkbox" id="abhaCreateHcwConsent" style="cursor:pointer;">
|
||||
<label class="form-check-label small text-dark mb-0" for="abhaCreateHcwConsent" style="cursor:pointer;">
|
||||
I, the healthcare worker, <strong id="abhaCreateHcwName"><?= esc($healthcareWorkerName) ?></strong>, confirm that I have duly informed and explained the beneficiary the contents of consent for the aforementioned purposes.
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check mt-2 d-flex align-items-center flex-wrap" id="abhaCreateBeneficiaryConsentWrap">
|
||||
<input class="form-check-input me-2 flex-shrink-0" type="checkbox" id="abhaCreateBeneficiaryConsent" style="cursor:pointer;">
|
||||
<label class="form-check-label small text-dark mb-0" for="abhaCreateBeneficiaryConsent" style="cursor:pointer;">
|
||||
I, <input type="text" class="form-control form-control-sm d-inline-block mx-1 fw-bold" id="abhaCreateBeneficiaryName" placeholder="Enter beneficiary name" autocomplete="name" style="width:170px; display:inline-block; vertical-align:middle; height:30px;" required> have been explained about the consent as stated above and hereby provide my consent for the aforementioned purposes. <span class="text-danger">*</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-danger small mt-1 d-none" id="abhaCreateConsentError">
|
||||
<i class="bi bi-exclamation-circle-fill me-1"></i>Consent is mandatory. Please check "I Agree" to proceed to the next step.
|
||||
<i class="bi bi-exclamation-circle-fill me-1"></i><span id="abhaCreateConsentErrorText">Consent is mandatory. Please enter beneficiary name and agree to all consent declarations.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -145,7 +189,6 @@
|
|||
<i class="bi bi-chat-dots-fill text-success" style="font-size:2.2rem"></i>
|
||||
<h6 class="mt-2 mb-1">Enter Aadhaar OTP</h6>
|
||||
<div class="text-muted small" id="abhaCreateOtpHint">We just sent an OTP on the Mobile Number linked with Aadhaar. Enter the OTP below to proceed with ABHA creation.</div>
|
||||
<div class="text-muted small mt-1 d-none" id="abhaCreateOtpRequestId"></div>
|
||||
</div>
|
||||
<label class="form-label fw-semibold" for="abhaCreateOtp">6-digit Aadhaar OTP</label>
|
||||
<div class="input-group input-group-lg">
|
||||
|
|
@ -298,10 +341,17 @@ window.AbhaCreateModal = (function () {
|
|||
if (/loginId/i.test(raw) && /invalid/i.test(raw)) {
|
||||
raw = 'Aadhaar Number is not valid. Valid 12-digit Aadhaar number is required.';
|
||||
}
|
||||
var message = escapeHtml(raw);
|
||||
return response && response.request_id
|
||||
? message + ' <small class="d-block mt-1">Bridge Request ID: ' + escapeHtml(response.request_id) + '</small>'
|
||||
: message;
|
||||
// ABDM M1: Map incorrect OTP errors to clear message without raw error codes
|
||||
if (/UIDAI Error code/i.test(raw) || /ABDM-1204/i.test(raw) || /attempts.*exceeded/i.test(raw) || /invalid.*otp/i.test(raw) || /incorrect.*otp/i.test(raw) || /otp.*match/i.test(raw) || /otp.*expired/i.test(raw)) {
|
||||
if (/attempts.*exceeded/i.test(raw) || /403/.test(raw)) {
|
||||
raw = 'Incorrect OTP. Maximum number of attempts exceeded. Please generate a fresh OTP and try again.';
|
||||
} else {
|
||||
raw = 'Incorrect OTP';
|
||||
}
|
||||
}
|
||||
// Strip any residual (Bridge Request ID: ...) or error code traces
|
||||
raw = raw.replace(/\s*\(Bridge Request ID:[^)]*\)/gi, '').replace(/^ABDM-\d+\s*:\s*/i, '');
|
||||
return escapeHtml(raw);
|
||||
}
|
||||
function validateVerhoeff(num) {
|
||||
num = digits(num);
|
||||
|
|
@ -429,15 +479,22 @@ window.AbhaCreateModal = (function () {
|
|||
function sendAadhaarOtp(isResend) {
|
||||
var aadhaar = digits($('#abhaCreateAadhaar').val());
|
||||
var mobile = digits($('#abhaCreateMobile').val());
|
||||
var beneficiaryName = $.trim($('#abhaCreateBeneficiaryName').val());
|
||||
var totalConsent = $('.abha-consent-chk').length;
|
||||
var checkedConsent = $('.abha-consent-chk:checked').length;
|
||||
var isAllConsentChecked = (totalConsent > 0 && checkedConsent === totalConsent) || $('#abhaCreateConsentAgree').is(':checked');
|
||||
var isHcwConsentChecked = $('#abhaCreateHcwConsent').is(':checked');
|
||||
var isBeneficiaryConsentChecked = $('#abhaCreateBeneficiaryConsent').is(':checked');
|
||||
|
||||
// Reset visual validation states
|
||||
$('#abhaCreateAadhaar').removeClass('is-invalid');
|
||||
$('#abhaCreateMobile').removeClass('is-invalid');
|
||||
$('#abhaCreateBeneficiaryName').removeClass('is-invalid');
|
||||
$('#abhaCreateConsentWrap').removeClass('border-danger');
|
||||
$('#abhaCreateConsentAgreeWrap').removeClass('border-danger');
|
||||
$('#abhaCreateDeclarationWrap').removeClass('border-danger');
|
||||
$('#abhaCreateHcwConsentWrap').removeClass('border-danger');
|
||||
$('#abhaCreateBeneficiaryConsentWrap').removeClass('border-danger');
|
||||
$('#abhaCreateConsentError').addClass('d-none');
|
||||
|
||||
if (aadhaar.length !== 12 || !validateVerhoeff(aadhaar)) {
|
||||
|
|
@ -450,6 +507,27 @@ window.AbhaCreateModal = (function () {
|
|||
alertBox('warning', 'Please enter a valid 10-digit mobile number for ABHA communication.');
|
||||
return;
|
||||
}
|
||||
if (beneficiaryName === '') {
|
||||
$('#abhaCreateBeneficiaryName').addClass('is-invalid').trigger('focus');
|
||||
$('#abhaCreateBeneficiaryConsentWrap').addClass('border-danger');
|
||||
$('#abhaCreateDeclarationWrap').addClass('border-danger');
|
||||
alertBox('warning', 'While creating an ABHA, the user is required to enter their name during the consent collection process.');
|
||||
return;
|
||||
}
|
||||
if (!isHcwConsentChecked) {
|
||||
$('#abhaCreateHcwConsentWrap').addClass('border-danger');
|
||||
$('#abhaCreateDeclarationWrap').addClass('border-danger');
|
||||
alertBox('warning', 'Please accept the healthcare worker consent declaration.');
|
||||
$('#abhaCreateHcwConsent').trigger('focus');
|
||||
return;
|
||||
}
|
||||
if (!isBeneficiaryConsentChecked) {
|
||||
$('#abhaCreateBeneficiaryConsentWrap').addClass('border-danger');
|
||||
$('#abhaCreateDeclarationWrap').addClass('border-danger');
|
||||
alertBox('warning', 'Please accept the beneficiary consent declaration.');
|
||||
$('#abhaCreateBeneficiaryConsent').trigger('focus');
|
||||
return;
|
||||
}
|
||||
if (!isAllConsentChecked) {
|
||||
$('#abhaCreateConsentWrap').addClass('border-danger');
|
||||
$('#abhaCreateConsentAgreeWrap').addClass('border-danger');
|
||||
|
|
@ -475,6 +553,7 @@ window.AbhaCreateModal = (function () {
|
|||
aadhaar: aadhaar,
|
||||
auth_type: 'aadhaar_otp',
|
||||
consent: 1,
|
||||
beneficiary_name: beneficiaryName,
|
||||
'<?= csrf_token() ?>': csrf()
|
||||
}, function (response) {
|
||||
button.prop('disabled', false).html('<i class="bi bi-send me-1"></i>Send OTP');
|
||||
|
|
@ -487,9 +566,6 @@ window.AbhaCreateModal = (function () {
|
|||
var destination = response.masked_mobile || ((response.message || '').match(/\*{2,}\d{4}/) || [''])[0] || '******XXXX';
|
||||
var promptMessage = 'We just sent an OTP on the Mobile Number ' + destination + ' linked with Aadhaar. Enter the OTP below to proceed with ABHA creation.';
|
||||
$('#abhaCreateOtpHint').text(promptMessage);
|
||||
$('#abhaCreateOtpRequestId')
|
||||
.toggleClass('d-none', !response.request_id)
|
||||
.text(response.request_id ? 'Bridge Request ID: ' + response.request_id : '');
|
||||
showStep(2);
|
||||
startResendTimer($('#abhaCreateResendBtn'), 60);
|
||||
$('#abhaCreateOtp').trigger('focus');
|
||||
|
|
@ -728,8 +804,12 @@ window.AbhaCreateModal = (function () {
|
|||
function clearConsentValidation() {
|
||||
$('#abhaCreateConsentWrap').removeClass('border-danger');
|
||||
$('#abhaCreateConsentAgreeWrap').removeClass('border-danger');
|
||||
$('#abhaCreateDeclarationWrap').removeClass('border-danger');
|
||||
$('#abhaCreateHcwConsentWrap').removeClass('border-danger');
|
||||
$('#abhaCreateBeneficiaryConsentWrap').removeClass('border-danger');
|
||||
$('#abhaCreateBeneficiaryName').removeClass('is-invalid');
|
||||
$('#abhaCreateConsentError').addClass('d-none');
|
||||
if ($('#abhaCreateAlert').text().indexOf('Consent is mandatory') !== -1) {
|
||||
if ($('#abhaCreateAlert').text().indexOf('Consent') !== -1 || $('#abhaCreateAlert').text().indexOf('beneficiary name') !== -1) {
|
||||
alertBox('', '');
|
||||
}
|
||||
}
|
||||
|
|
@ -737,6 +817,12 @@ window.AbhaCreateModal = (function () {
|
|||
$('#abhaCreateConsentAgree').on('change', function () {
|
||||
var checked = $(this).is(':checked');
|
||||
$('.abha-consent-chk').prop('checked', checked);
|
||||
$('#abhaCreateHcwConsent').prop('checked', checked);
|
||||
if (checked && $.trim($('#abhaCreateBeneficiaryName').val()) !== '') {
|
||||
$('#abhaCreateBeneficiaryConsent').prop('checked', true);
|
||||
} else if (!checked) {
|
||||
$('#abhaCreateBeneficiaryConsent').prop('checked', false);
|
||||
}
|
||||
$('#abhaCreateSelectAllConsent').text(checked ? 'Deselect All' : 'Select All');
|
||||
if (checked) {
|
||||
clearConsentValidation();
|
||||
|
|
@ -755,17 +841,34 @@ window.AbhaCreateModal = (function () {
|
|||
});
|
||||
|
||||
$('#abhaCreateSelectAllConsent').on('click', function () {
|
||||
var total = $('.abha-consent-chk').length;
|
||||
var checked = $('.abha-consent-chk:checked').length;
|
||||
var total = $('.abha-consent-chk').length + 2;
|
||||
var checked = $('.abha-consent-chk:checked').length + ($('#abhaCreateHcwConsent').is(':checked') ? 1 : 0) + ($('#abhaCreateBeneficiaryConsent').is(':checked') ? 1 : 0);
|
||||
var shouldCheck = (checked < total);
|
||||
$('.abha-consent-chk').prop('checked', shouldCheck);
|
||||
$('#abhaCreateConsentAgree').prop('checked', shouldCheck);
|
||||
$('#abhaCreateHcwConsent').prop('checked', shouldCheck);
|
||||
$('#abhaCreateBeneficiaryConsent').prop('checked', shouldCheck);
|
||||
$(this).text(shouldCheck ? 'Deselect All' : 'Select All');
|
||||
if (shouldCheck) {
|
||||
clearConsentValidation();
|
||||
}
|
||||
});
|
||||
|
||||
$('#abhaCreateBeneficiaryName').on('click', function (e) {
|
||||
e.stopPropagation();
|
||||
}).on('input', function () {
|
||||
$(this).removeClass('is-invalid');
|
||||
if ($.trim($(this).val()) !== '') {
|
||||
$('#abhaCreateBeneficiaryConsent').prop('checked', true);
|
||||
$('#abhaCreateBeneficiaryConsentWrap').removeClass('border-danger');
|
||||
}
|
||||
clearConsentValidation();
|
||||
});
|
||||
|
||||
$('#abhaCreateHcwConsent, #abhaCreateBeneficiaryConsent').on('change', function () {
|
||||
clearConsentValidation();
|
||||
});
|
||||
|
||||
$('#abhaCreateAadhaar').on('input', function () {
|
||||
$(this).removeClass('is-invalid');
|
||||
if ($('#abhaCreateAlert').text().indexOf('Aadhaar Number is not valid') !== -1) {
|
||||
|
|
@ -825,7 +928,7 @@ window.AbhaCreateModal = (function () {
|
|||
});
|
||||
|
||||
return {
|
||||
open: function (callback, prefillMobile) {
|
||||
open: function (callback, prefillMobile, prefillName, prefillHcwName) {
|
||||
onCompleted = callback;
|
||||
createTxnId = '';
|
||||
mobileTxnId = '';
|
||||
|
|
@ -836,9 +939,12 @@ window.AbhaCreateModal = (function () {
|
|||
stopTimers();
|
||||
$('#abhaCreateAadhaar,#abhaCreateMobile,#abhaCreateOtp,#abhaCreateMobileOtp,#abhaCreateCustomAddress').val('').removeClass('is-invalid');
|
||||
$('#abhaCreateMobile').val(digits(prefillMobile));
|
||||
$('#abhaCreateOtpRequestId').addClass('d-none').text('');
|
||||
$('#abhaCreateConsent1,#abhaCreateConsent2,#abhaCreateConsent3,#abhaCreateConsent4,#abhaCreateConsentAgree').prop('checked', false);
|
||||
$('#abhaCreateConsentWrap,#abhaCreateConsentAgreeWrap').removeClass('border-danger');
|
||||
$('#abhaCreateBeneficiaryName').val(prefillName ? String(prefillName).trim() : '').removeClass('is-invalid');
|
||||
if (prefillHcwName) {
|
||||
$('#abhaCreateHcwName').text(prefillHcwName);
|
||||
}
|
||||
$('#abhaCreateConsent1,#abhaCreateConsent2,#abhaCreateConsent3,#abhaCreateConsent4,#abhaCreateConsentAgree,#abhaCreateHcwConsent,#abhaCreateBeneficiaryConsent').prop('checked', false);
|
||||
$('#abhaCreateConsentWrap,#abhaCreateConsentAgreeWrap,#abhaCreateDeclarationWrap,#abhaCreateHcwConsentWrap,#abhaCreateBeneficiaryConsentWrap').removeClass('border-danger');
|
||||
$('#abhaCreateConsentError').addClass('d-none');
|
||||
$('#abhaCreateSelectAllConsent').text('Select All');
|
||||
$('#abhaCreatePhoto,#abhaCreateDownloadCard').addClass('d-none');
|
||||
|
|
|
|||
|
|
@ -255,7 +255,18 @@ window.AbhaMobileModal = (function () {
|
|||
}
|
||||
function digits(value) { return String(value == null ? '' : value).replace(/\D/g, ''); }
|
||||
function apiMessage(response, fallback) {
|
||||
return response && (response.error_text || response.message) ? escapeHtml(response.error_text || response.message) : fallback;
|
||||
var raw = response && (response.error_text || response.message)
|
||||
? String(response.error_text || response.message)
|
||||
: fallback;
|
||||
if (/UIDAI Error code/i.test(raw) || /ABDM-1204/i.test(raw) || /attempts.*exceeded/i.test(raw) || /invalid.*otp/i.test(raw) || /incorrect.*otp/i.test(raw) || /otp.*match/i.test(raw) || /otp.*expired/i.test(raw)) {
|
||||
if (/attempts.*exceeded/i.test(raw) || /403/.test(raw)) {
|
||||
raw = 'Incorrect OTP. Maximum number of attempts exceeded. Please generate a fresh OTP and try again.';
|
||||
} else {
|
||||
raw = 'Incorrect OTP';
|
||||
}
|
||||
}
|
||||
raw = raw.replace(/\s*\(Bridge Request ID:[^)]*\)/gi, '').replace(/^ABDM-\d+\s*:\s*/i, '');
|
||||
return escapeHtml(raw);
|
||||
}
|
||||
function alertBox(type, message) {
|
||||
var alertEl = document.getElementById('abhaMobileAlert');
|
||||
|
|
|
|||
|
|
@ -117,7 +117,18 @@ window.AbhaVerifyModal = (function () {
|
|||
}
|
||||
function escapeHtml(value) { return $('<div>').text(value == null ? '' : String(value)).html(); }
|
||||
function apiMessage(response, fallback) {
|
||||
return response && (response.error_text || response.message) ? escapeHtml(response.error_text || response.message) : fallback;
|
||||
var raw = response && (response.error_text || response.message)
|
||||
? String(response.error_text || response.message)
|
||||
: fallback;
|
||||
if (/UIDAI Error code/i.test(raw) || /ABDM-1204/i.test(raw) || /attempts.*exceeded/i.test(raw) || /invalid.*otp/i.test(raw) || /incorrect.*otp/i.test(raw) || /otp.*match/i.test(raw) || /otp.*expired/i.test(raw)) {
|
||||
if (/attempts.*exceeded/i.test(raw) || /403/.test(raw)) {
|
||||
raw = 'Incorrect OTP. Maximum number of attempts exceeded. Please generate a fresh OTP and try again.';
|
||||
} else {
|
||||
raw = 'Incorrect OTP';
|
||||
}
|
||||
}
|
||||
raw = raw.replace(/\s*\(Bridge Request ID:[^)]*\)/gi, '').replace(/^ABDM-\d+\s*:\s*/i, '');
|
||||
return escapeHtml(raw);
|
||||
}
|
||||
function alertBox(type, message) { $('#abhaVerifyAlert').html(message ? '<div class="alert alert-' + type + ' py-2">' + message + '</div>' : ''); }
|
||||
function showStep(step) {
|
||||
|
|
|
|||
65
tests/unit/Abdm/AbhaOtpErrorHandlingTest.php
Normal file
65
tests/unit/Abdm/AbhaOtpErrorHandlingTest.php
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Unit\Abdm;
|
||||
|
||||
use App\Controllers\Abha;
|
||||
use CodeIgniter\Test\CIUnitTestCase;
|
||||
use ReflectionClass;
|
||||
|
||||
final class AbhaOtpErrorHandlingTest extends CIUnitTestCase
|
||||
{
|
||||
private Abha $controller;
|
||||
private \ReflectionMethod $extractMethod;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->controller = new Abha();
|
||||
$ref = new ReflectionClass($this->controller);
|
||||
$this->extractMethod = $ref->getMethod('extractBridgeErrorText');
|
||||
$this->extractMethod->setAccessible(true);
|
||||
}
|
||||
|
||||
public function testExtractBridgeErrorTextMapsUidai400ToIncorrectOtp(): void
|
||||
{
|
||||
$payload = [
|
||||
'error' => [
|
||||
'code' => 'ABDM-1204',
|
||||
'message' => 'UIDAI Error code : 400 : Invalid Aadhaar OTP value.',
|
||||
],
|
||||
];
|
||||
|
||||
$result = $this->extractMethod->invoke($this->controller, $payload, 'Please enter a valid OTP.');
|
||||
$this->assertSame('Incorrect OTP', $result);
|
||||
}
|
||||
|
||||
public function testExtractBridgeErrorTextMapsUidai403ToAttemptsExceeded(): void
|
||||
{
|
||||
$payload = [
|
||||
'error_text' => 'UIDAI Error code : 403 : Maximum number of attempts for OTP match is exceeded or OTP is not generated. Please generate a fresh OTP and try to authenticate again',
|
||||
];
|
||||
|
||||
$result = $this->extractMethod->invoke($this->controller, $payload, 'Please enter a valid OTP.');
|
||||
$this->assertStringContainsString('Incorrect OTP', $result);
|
||||
$this->assertStringContainsString('Maximum number of attempts exceeded', $result);
|
||||
$this->assertStringNotContainsString('403', $result);
|
||||
$this->assertStringNotContainsString('UIDAI Error code', $result);
|
||||
}
|
||||
|
||||
public function testExtractBridgeErrorTextStripsRawErrorCodesFromGenericOtpError(): void
|
||||
{
|
||||
$payload = [
|
||||
'message' => 'ABDM-1204 : Invalid OTP entered by user',
|
||||
];
|
||||
|
||||
$result = $this->extractMethod->invoke($this->controller, $payload, 'Please enter a valid OTP.');
|
||||
$this->assertSame('Incorrect OTP', $result);
|
||||
}
|
||||
|
||||
public function testExtractBridgeErrorTextFallbackNormalizesOtpText(): void
|
||||
{
|
||||
$payload = [];
|
||||
$result = $this->extractMethod->invoke($this->controller, $payload, 'Please enter a valid OTP. Entered OTP is either expired or incorrect.');
|
||||
$this->assertSame('Incorrect OTP', $result);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user