id, $application->created_at, $application->state, $application->merchant_id)) { return; } $redis = new RawRedisConnector(); $key = DatapointHelper::datapointKey($application->id); // Field names are the consumer_application column names — see // DatapointHelper::$approvalRequired. $fieldsData = [ 'name' => !empty($application->name) ? 1 : 0, 'dob' => !empty($application->dob) ? 1 : 0, 'pan_card' => !empty($application->pan_card) ? 1 : 0, 'monthly_income' => !empty($application->monthly_income) ? 1 : 0, 'loan_amount' => !empty($application->loan_amount) ? 1 : 0, 'employee_status' => !empty($application->employee_status) ? 1 : 0, 'offer_id' => !empty($application->offer_id) ? 1 : 0, 'company_name' => !empty($application->company_name) ? 1 : 0, 'current_address_line_1' => !empty($application->current_address_line_1) ? 1 : 0, 'current_address_pincode' => !empty($application->current_address_pincode) ? 1 : 0, 'current_address_state' => !empty($application->current_address_state) ? 1 : 0, 'current_address_city' => !empty($application->current_address_city) ? 1 : 0, // Co-applicant rejection tier. The co-applicant is optional, so // on an application without one these all stay 0 and // DatapointHelper::hasCoApplicant() reads co_applicant_name to // keep the whole co-applicant half dormant. // // co_applicant_pan_card and co_applicant_mobile_number are // encrypted attributes; the model decrypts them on read, so // !empty() sees plaintext here and ciphertext in // buildFromDatabase(). Both agree, because Encryptable only // encrypts a non-empty value. 'co_applicant_name' => !empty($application->co_applicant_name) ? 1 : 0, 'co_applicant_dob' => !empty($application->co_applicant_dob) ? 1 : 0, 'co_applicant_pan_card' => !empty($application->co_applicant_pan_card) ? 1 : 0, 'co_applicant_mobile_number' => !empty($application->co_applicant_mobile_number) ? 1 : 0, 'co_applicant_monthly_income' => !empty($application->co_applicant_monthly_income) ? 1 : 0, 'co_applicant_address_pincode' => !empty($application->co_applicant_address_pincode) ? 1 : 0, ]; // write() records the flags, refreshes the TTL, and fires the // readiness notification when the hash was cold or a flag flipped. // The notification covers both applicant types; dispatch does not. DatapointHelper::write($redis, $application->id, $fieldsData); // Applicant type 1 only, and deliberately so even though this // observer writes the co-applicant flags too. The co-applicant tier // must not dispatch before co-applicant consent exists, or its // bureau pull fails and the guard is spent — so type 2 is dispatched // only from the consent paths. See $coApplicantRejectionRequired. DatapointHelper::maybeDispatch($application->id, $redis, $key, $fieldsData, 1); } catch (\Exception $e) { DatapointHelper::log(['title' => 'Redis-Cache', 'message' => 'DatapointHelper: readiness notification failed', 'error' => $e->getMessage(), 'line' => $e->getLine(), 'trace' => $e->getTraceAsString(), 'application_id' => $application->id]); } } }