From 1153193723368dc400edb980ddf0cac598a5fc58 Mon Sep 17 00:00:00 2001 From: androidlover5842 Date: Thu, 5 Feb 2026 19:52:35 +0530 Subject: [PATCH] Resolve pincode from local DB before external fallbacks --- .../document/DocumentExtractionService.kt | 7 ++ .../geo/LocalPincodeDirectoryClient.kt | 76 +++++++++++++++++++ .../component/geo/PincodeResolver.kt | 23 ++++-- 3 files changed, 98 insertions(+), 8 deletions(-) create mode 100644 src/main/kotlin/com/android/trisolarisserver/component/geo/LocalPincodeDirectoryClient.kt diff --git a/src/main/kotlin/com/android/trisolarisserver/component/document/DocumentExtractionService.kt b/src/main/kotlin/com/android/trisolarisserver/component/document/DocumentExtractionService.kt index 6d062d4..8a62fa5 100644 --- a/src/main/kotlin/com/android/trisolarisserver/component/document/DocumentExtractionService.kt +++ b/src/main/kotlin/com/android/trisolarisserver/component/document/DocumentExtractionService.kt @@ -639,6 +639,13 @@ class DocumentExtractionService( tertiary.errorMessage?.let { results["geoTertiaryError"] = it.take(300) } tertiary.requestUrl?.let { results["geoTertiaryUrl"] = it.take(500) } } + resolvedResult.quaternary?.let { quaternary -> + results["geoQuaternarySource"] = quaternary.source + quaternary.status?.let { results["geoQuaternaryStatus"] = it } + quaternary.rawResponse?.let { results["geoQuaternaryResponse"] = it.take(4000) } + quaternary.errorMessage?.let { results["geoQuaternaryError"] = it.take(300) } + quaternary.requestUrl?.let { results["geoQuaternaryUrl"] = it.take(500) } + } val resolved = resolvedResult.resolved()?.resolvedCityState ?: return results["geoResolved"] = resolved results["geoSource"] = resolvedResult.resolved()?.source ?: "" diff --git a/src/main/kotlin/com/android/trisolarisserver/component/geo/LocalPincodeDirectoryClient.kt b/src/main/kotlin/com/android/trisolarisserver/component/geo/LocalPincodeDirectoryClient.kt new file mode 100644 index 0000000..770ffd2 --- /dev/null +++ b/src/main/kotlin/com/android/trisolarisserver/component/geo/LocalPincodeDirectoryClient.kt @@ -0,0 +1,76 @@ +package com.android.trisolarisserver.component.geo + +import org.slf4j.LoggerFactory +import org.springframework.jdbc.core.JdbcTemplate +import org.springframework.stereotype.Component + +@Component +class LocalPincodeDirectoryClient( + private val jdbcTemplate: JdbcTemplate +) { + private val logger = LoggerFactory.getLogger(LocalPincodeDirectoryClient::class.java) + + fun resolve(pinCode: String): PincodeLookupResult { + val normalizedPin = pinCode.trim() + if (!PIN_REGEX.matches(normalizedPin)) { + return PincodeLookupResult( + resolvedCityState = null, + rawResponse = null, + status = "INVALID_PIN", + source = "local-db", + errorMessage = "PIN must be 6 digits" + ) + } + + return try { + val rows = jdbcTemplate.query( + """ + select city, state + from india_pincode_city_state + where pincode = ? + and nullif(trim(city), '') is not null + and nullif(trim(state), '') is not null + group by city, state + order by count(*) desc, city asc, state asc + limit 1 + """.trimIndent(), + { rs, _ -> + val city = rs.getString("city")?.trim()?.ifBlank { null } + val state = rs.getString("state")?.trim()?.ifBlank { null } + if (city == null || state == null) null else "$city, $state" + }, + normalizedPin.toInt() + ).filterNotNull() + + val resolved = rows.firstOrNull() + if (resolved != null) { + PincodeLookupResult( + resolvedCityState = resolved, + rawResponse = null, + status = "OK", + source = "local-db" + ) + } else { + PincodeLookupResult( + resolvedCityState = null, + rawResponse = null, + status = "ZERO_RESULTS", + source = "local-db" + ) + } + } catch (ex: Exception) { + logger.warn("Local pincode lookup failed: {}", ex.message) + PincodeLookupResult( + resolvedCityState = null, + rawResponse = null, + status = "ERROR", + source = "local-db", + errorMessage = ex.message + ) + } + } + + companion object { + private val PIN_REGEX = Regex("\\d{6}") + } +} diff --git a/src/main/kotlin/com/android/trisolarisserver/component/geo/PincodeResolver.kt b/src/main/kotlin/com/android/trisolarisserver/component/geo/PincodeResolver.kt index 061a3b1..e55673f 100644 --- a/src/main/kotlin/com/android/trisolarisserver/component/geo/PincodeResolver.kt +++ b/src/main/kotlin/com/android/trisolarisserver/component/geo/PincodeResolver.kt @@ -4,38 +4,45 @@ import org.springframework.stereotype.Component @Component class PincodeResolver( + private val localPincodeDirectoryClient: LocalPincodeDirectoryClient, private val dataGovPincodeClient: DataGovPincodeClient, private val postalPincodeClient: PostalPincodeClient, private val googleGeocodingClient: GoogleGeocodingClient ) { fun resolve(pinCode: String): PincodeResolveResult { - val primary = dataGovPincodeClient.resolve(pinCode) + val primary = localPincodeDirectoryClient.resolve(pinCode) if (primary.status == "OK" && primary.resolvedCityState != null) { - return PincodeResolveResult(primary, null, null) + return PincodeResolveResult(primary, null, null, null) } - val secondary = postalPincodeClient.resolve(pinCode) + val secondary = dataGovPincodeClient.resolve(pinCode) if (secondary.status == "OK" && secondary.resolvedCityState != null) { - return PincodeResolveResult(primary, secondary, null) + return PincodeResolveResult(primary, secondary, null, null) + } + + val tertiary = postalPincodeClient.resolve(pinCode) + if (tertiary.status == "OK" && tertiary.resolvedCityState != null) { + return PincodeResolveResult(primary, secondary, tertiary, null) } val google = googleGeocodingClient.resolveCityState(pinCode) - val tertiary = PincodeLookupResult( + val quaternary = PincodeLookupResult( google.resolvedCityState, google.rawResponse, google.status, "google" ) - return PincodeResolveResult(primary, secondary, tertiary) + return PincodeResolveResult(primary, secondary, tertiary, quaternary) } } data class PincodeResolveResult( val primary: PincodeLookupResult, val secondary: PincodeLookupResult?, - val tertiary: PincodeLookupResult? + val tertiary: PincodeLookupResult?, + val quaternary: PincodeLookupResult? ) { fun resolved(): PincodeLookupResult? { - return sequenceOf(primary, secondary, tertiary).firstOrNull { it?.resolvedCityState != null } + return sequenceOf(primary, secondary, tertiary, quaternary).firstOrNull { it?.resolvedCityState != null } } }