Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lib/mobility-core/mobility-core.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -329,12 +329,15 @@ library
Kernel.External.Verification.Interface.HyperVerge
Kernel.External.Verification.Interface.Idfy
Kernel.External.Verification.Interface.InternalScripts
Kernel.External.Verification.Interface.Morth
Kernel.External.Verification.Interface.SafetyPortal
Kernel.External.Verification.Interface.Tten
Kernel.External.Verification.Interface.Types
Kernel.External.Verification.InternalScripts.Error
Kernel.External.Verification.InternalScripts.FaceVerification
Kernel.External.Verification.InternalScripts.Types
Kernel.External.Verification.Morth.Flow
Kernel.External.Verification.Morth.Types
Kernel.External.Verification.SafetyPortal.API
Kernel.External.Verification.SafetyPortal.Client
Kernel.External.Verification.SafetyPortal.Config
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,24 +35,30 @@ verifyRC req = do
res <- QGD.findByRCNumber req.rcNumber >>= fromMaybeM (InternalError "rcNumber is not found in GovtData.")
pure $
SyncResp
VT.RCVerificationResponse
{ registrationDate = Nothing,
registrationNumber = res.registrationNumber,
fitnessUpto = res.permitValidityUpto,
insuranceValidity = res.permitValidityUpto,
vehicleClass = res.bodyType,
vehicleCategory = Nothing,
seatingCapacity = toJSON <$> res.seatingCapacity,
manufacturer = res.manufacturer,
permitValidityFrom = res.permitValidityFrom,
permitValidityUpto = res.permitValidityUpto,
pucValidityUpto = Nothing,
manufacturerModel = res.manufacturerModel,
mYManufacturing = Nothing,
color = Nothing,
fuelType = res.fuelType,
bodyType = res.bodyType,
status = Nothing,
grossVehicleWeight = Nothing,
unladdenWeight = Nothing
VerifySyncResp
{ requestId = Nothing,
requestor = VT.GovtData,
transactionId = Nothing,
response =
VT.RCVerificationResponse
{ registrationDate = Nothing,
registrationNumber = res.registrationNumber,
fitnessUpto = res.permitValidityUpto,
insuranceValidity = res.permitValidityUpto,
vehicleClass = res.bodyType,
vehicleCategory = Nothing,
seatingCapacity = toJSON <$> res.seatingCapacity,
manufacturer = res.manufacturer,
permitValidityFrom = res.permitValidityFrom,
permitValidityUpto = res.permitValidityUpto,
pucValidityUpto = Nothing,
manufacturerModel = res.manufacturerModel,
mYManufacturing = Nothing,
color = Nothing,
fuelType = res.fuelType,
bodyType = res.bodyType,
status = Nothing,
grossVehicleWeight = Nothing,
unladdenWeight = Nothing
}
}
52 changes: 47 additions & 5 deletions lib/mobility-core/src/Kernel/External/Verification/Interface.hs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ module Kernel.External.Verification.Interface
fetchAndExtractVerifiedPan,
fetchAndExtractVerifiedAadhaar,
getVerifiedAadhaarXML,
verifyRCMorth,
)
where

Expand All @@ -56,6 +57,7 @@ import qualified Kernel.External.Verification.Interface.Digilocker as DigiLocker
import qualified Kernel.External.Verification.Interface.HyperVerge as HyperVerge
import qualified Kernel.External.Verification.Interface.Idfy as Idfy
import qualified Kernel.External.Verification.Interface.InternalScripts as IS
import qualified Kernel.External.Verification.Interface.Morth as Morth
import qualified Kernel.External.Verification.Interface.SafetyPortal as SafetyPortal
import qualified Kernel.External.Verification.Interface.Tten as Tten
import Kernel.External.Verification.Interface.Types as Reexport
Expand Down Expand Up @@ -84,6 +86,7 @@ verifyDLAsync serviceConfig req = case serviceConfig of
HyperVergeVerificationConfigRCDL cfg -> HyperVerge.verifyDLAsync cfg req
DigiLockerConfig _ -> throwError $ InternalError "Not Implemented!"
TtenVerificationConfig _ -> throwError $ InternalError "Not Implemented!"
MorthConfig _ -> throwError $ InternalError "Not Implemented!"

verifyPanAsync ::
( EncFlow m r,
Expand All @@ -102,6 +105,7 @@ verifyPanAsync serviceConfig req = case serviceConfig of
HyperVergeVerificationConfigRCDL _ -> throwError $ InternalError "Not Implemented!"
DigiLockerConfig _ -> throwError $ InternalError "Not Implemented!"
TtenVerificationConfig _ -> throwError $ InternalError "Not Implemented!"
MorthConfig _ -> throwError $ InternalError "Not Implemented!"

verifyGstAsync ::
( EncFlow m r,
Expand All @@ -120,6 +124,7 @@ verifyGstAsync serviceConfig req = case serviceConfig of
HyperVergeVerificationConfigRCDL _ -> throwError $ InternalError "Not Implemented!"
DigiLockerConfig _ -> throwError $ InternalError "Not Implemented!"
TtenVerificationConfig _ -> throwError $ InternalError "Not Implemented!"
MorthConfig _ -> throwError $ InternalError "Not Implemented!"

verifyBankAccountAsync ::
( EncFlow m r,
Expand All @@ -138,6 +143,7 @@ verifyBankAccountAsync serviceConfig req = case serviceConfig of
HyperVergeVerificationConfigRCDL _ -> throwError $ InternalError "Not Implemented!"
DigiLockerConfig _ -> throwError $ InternalError "Not Implemented!"
TtenVerificationConfig _ -> throwError $ InternalError "Not Implemented!"
MorthConfig _ -> throwError $ InternalError "Not Implemented!"

verifyPanAadhaarLinkAsync ::
( EncFlow m r,
Expand All @@ -156,6 +162,7 @@ verifyPanAadhaarLinkAsync serviceConfig req = case serviceConfig of
HyperVergeVerificationConfigRCDL _ -> throwError $ InternalError "Not Implemented!"
DigiLockerConfig _ -> throwError $ InternalError "Not Implemented!"
TtenVerificationConfig _ -> throwError $ InternalError "Not Implemented!"
MorthConfig _ -> throwError $ InternalError "Not Implemented!"

verifyUdyamAadhaarAsync ::
( EncFlow m r,
Expand All @@ -174,6 +181,7 @@ verifyUdyamAadhaarAsync serviceConfig req = case serviceConfig of
HyperVergeVerificationConfigRCDL _ -> throwError $ InternalError "Not Implemented!"
DigiLockerConfig _ -> throwError $ InternalError "Not Implemented!"
TtenVerificationConfig _ -> throwError $ InternalError "Not Implemented!"
MorthConfig _ -> throwError $ InternalError "Not Implemented!"

verifyRC ::
( EncFlow m r,
Expand All @@ -195,11 +203,16 @@ verifyRC getServiceConfig verificationProvidersPriorityList req = do
where
verifyRCWithFallback [] = throwError $ InternalError "Not able to verify the RC with all the configured providers !!!!!"
verifyRCWithFallback (preferredProvider : restProviders) = do
logDebug $ "Calling verifyRC for provider : " <> show preferredProvider
result <- withTryCatch "verifyRC" $ getServiceConfig preferredProvider >>= flip verifyRC' req
case result of
Left _ -> verifyRCWithFallback restProviders
Right res -> return $ RCRespWithRemPriorityList res restProviders
-- Morth requires engineNumber; skip to next provider if missing, Case case is when UI is not 100% released
let skipMorth = preferredProvider == Morth && isNothing req.engineNumber
if skipMorth
then verifyRCWithFallback restProviders
else do
logDebug $ "Calling verifyRC for provider : " <> show preferredProvider
result <- withTryCatch "verifyRC" $ getServiceConfig preferredProvider >>= flip verifyRC' req
case result of
Left _ -> verifyRCWithFallback restProviders
Right res -> return $ RCRespWithRemPriorityList res restProviders

verifyRC' ::
( EncFlow m r,
Expand All @@ -222,6 +235,7 @@ verifyRC' serviceConfig req = case serviceConfig of
HyperVergeVerificationConfigRCDL cfg -> HyperVerge.verifyRCAsync cfg req
DigiLockerConfig _ -> throwError $ InternalError "Not Implemented!"
TtenVerificationConfig cfg -> Tten.verifyTten cfg req
MorthConfig cfg -> Morth.verifyRCAsync cfg req

validateImage ::
( EncFlow m r,
Expand All @@ -240,6 +254,7 @@ validateImage serviceConfig req = case serviceConfig of
HyperVergeVerificationConfigRCDL _ -> throwError $ InternalError "Not Implemented!"
DigiLockerConfig _ -> throwError $ InternalError "Not Implemented!"
TtenVerificationConfig _ -> throwError $ InternalError "Not Implemented!"
MorthConfig _ -> throwError $ InternalError "Not Implemented!"

validateFaceImage ::
( CoreMetrics m,
Expand All @@ -258,6 +273,7 @@ validateFaceImage serviceConfig req = case serviceConfig of
HyperVergeVerificationConfigRCDL _ -> throwError $ InternalError "Not Implemented!"
DigiLockerConfig _ -> throwError $ InternalError "Not Implemented!"
TtenVerificationConfig _ -> throwError $ InternalError "Not Implemented!"
MorthConfig _ -> throwError $ InternalError "Not Implemented!"

extractRCImage ::
( EncFlow m r,
Expand All @@ -276,6 +292,7 @@ extractRCImage serviceConfig req = case serviceConfig of
HyperVergeVerificationConfigRCDL _ -> throwError $ InternalError "Not Implemented!"
DigiLockerConfig _ -> throwError $ InternalError "Not Implemented!"
TtenVerificationConfig _ -> throwError $ InternalError "Not Implemented!"
MorthConfig _ -> throwError $ InternalError "Not Implemented!"

extractDLImage ::
( EncFlow m r,
Expand All @@ -294,6 +311,7 @@ extractDLImage serviceConfig req = case serviceConfig of
HyperVergeVerificationConfigRCDL _ -> throwError $ InternalError "Not Implemented!"
DigiLockerConfig _ -> throwError $ InternalError "Not Implemented!"
TtenVerificationConfig _ -> throwError $ InternalError "Not Implemented!"
MorthConfig _ -> throwError $ InternalError "Not Implemented!"

extractPanImage ::
( EncFlow m r,
Expand All @@ -312,6 +330,7 @@ extractPanImage serviceConfig req = case serviceConfig of
HyperVergeVerificationConfigRCDL _ -> throwError $ InternalError "Not Implemented!"
DigiLockerConfig _ -> throwError $ InternalError "Not Implemented!"
TtenVerificationConfig _ -> throwError $ InternalError "Not Implemented!"
MorthConfig _ -> throwError $ InternalError "Not Implemented!"

extractGSTImage ::
( EncFlow m r,
Expand All @@ -330,6 +349,7 @@ extractGSTImage serviceConfig req = case serviceConfig of
HyperVergeVerificationConfigRCDL _ -> throwError $ InternalError "Not Implemented!"
DigiLockerConfig _ -> throwError $ InternalError "Not Implemented!"
TtenVerificationConfig _ -> throwError $ InternalError "Not Implemented!"
MorthConfig _ -> throwError $ InternalError "Not Implemented!"

extractUdyogAadhaarAsync ::
( EncFlow m r,
Expand All @@ -348,6 +368,7 @@ extractUdyogAadhaarAsync serviceConfig req = case serviceConfig of
HyperVergeVerificationConfigRCDL _ -> throwError $ InternalError "Not Implemented!"
DigiLockerConfig _ -> throwError $ InternalError "Not Implemented!"
TtenVerificationConfig _ -> throwError $ InternalError "Not Implemented!"
MorthConfig _ -> throwError $ InternalError "Not Implemented!"

extractAadhaarImage ::
( EncFlow m r,
Expand All @@ -366,6 +387,7 @@ extractAadhaarImage serviceConfig req = case serviceConfig of
HyperVergeVerificationConfigRCDL _ -> throwError $ InternalError "Not Implemented!"
DigiLockerConfig _ -> throwError $ InternalError "Not Implemented!"
TtenVerificationConfig _ -> throwError $ InternalError "Not Implemented!"
MorthConfig _ -> throwError $ InternalError "Not Implemented!"

nameCompare ::
( EncFlow m r,
Expand All @@ -384,6 +406,7 @@ nameCompare serviceConfig req = case serviceConfig of
HyperVergeVerificationConfigRCDL _ -> throwError $ InternalError "Not Implemented!"
DigiLockerConfig _ -> throwError $ InternalError "Not Implemented!"
TtenVerificationConfig _ -> throwError $ InternalError "Not Implemented!"
MorthConfig _ -> throwError $ InternalError "Not Implemented!"

searchAgent ::
( EncFlow m r,
Expand Down Expand Up @@ -414,6 +437,7 @@ verifySdkResp serviceConfig req = case serviceConfig of
HyperVergeVerificationConfigRCDL _ -> throwError $ InternalError "Not Implemented!"
DigiLockerConfig _ -> throwError $ InternalError "Not Implemented!"
TtenVerificationConfig _ -> throwError $ InternalError "Not Implemented!"
MorthConfig _ -> throwError $ InternalError "Not Implemented!"

getTask ::
( EncFlow m r,
Expand All @@ -433,6 +457,7 @@ getTask serviceConfig req updateResp = case serviceConfig of
HyperVergeVerificationConfigRCDL cfg -> HyperVerge.getVerificationStatus cfg req updateResp
DigiLockerConfig _ -> throwError $ InternalError "Not Implemented!"
TtenVerificationConfig _ -> throwError $ InternalError "Not Implemented!"
MorthConfig _ -> throwError $ InternalError "Not Implemented!"

fetchAndExtractVerifiedDL ::
( EncFlow m r,
Expand Down Expand Up @@ -529,3 +554,20 @@ getVerifiedAadhaarXML ::
getVerifiedAadhaarXML serviceConfig req = case serviceConfig of
DigiLockerConfig cfg -> DigiLocker.getVerifiedAadhaarXML cfg req.accessToken
_ -> throwError $ InternalError "Not Implemented!"

-- | Dedicated entry-point for the MoRTH vehicle-RC validity check.
-- Unlike the generic 'verifyRC' / 'verifyRC'' dispatch this function accepts
-- a 'MorthConfig' directly so callers do not need to wire it through the
-- priority-list mechanism.
verifyRCMorth ::
( EncFlow m r,
CoreMetrics m,
HasRequestId r,
MonadReader r m
) =>
VerificationServiceConfig ->
VerifyRCReq ->
m VerifyRCResp
verifyRCMorth serviceConfig req = case serviceConfig of
MorthConfig cfg -> Morth.verifyRCAsync cfg req
_ -> throwError $ InternalError "verifyRCMorth: MorthConfig expected but a different provider was supplied"
Original file line number Diff line number Diff line change
Expand Up @@ -323,8 +323,22 @@ extractRCImage cfg req = do
pure
ExtractRCImageResp
{ extractedRC =
resp.result <&> \result -> do
ExtractedRC {rcNumber = result.extraction_output.registration_number}
resp.result <&> \result ->
let eo = result.extraction_output
in ExtractedRC
{ rcNumber = eo.registration_number,
vehicleClass = eo._class,
manufacturer = eo.manufacturer,
model = eo.model,
fuelType = eo.fuel,
colour = eo.colour,
chassisNumber = eo.chassis_number,
engineNumber = eo.engine_number,
registrationDate = eo.registration_date,
ownerName = eo.owner_name,
manufacturingDate = eo.manufacturing_date,
bodyType = eo.body
}
}

extractUdyogAadhaarAsync ::
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
{-
Copyright 2022-23, Juspay India Pvt Ltd

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License

as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is

distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS

FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero

General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
-}

module Kernel.External.Verification.Interface.Morth where

import Kernel.External.Encryption
import qualified Kernel.External.Verification.Interface.Types as InterfaceTypes
import qualified Kernel.External.Verification.Morth.Flow as MorthFlow
import Kernel.External.Verification.Morth.Types
import qualified Kernel.External.Verification.Types as VT
import Kernel.Prelude
import Kernel.Tools.Metrics.CoreMetrics (CoreMetrics)
import Kernel.Types.Error (MorthError (..))
import Kernel.Utils.Error.Throwing (throwError)
import Kernel.Utils.Servant.Client

-- | Verify vehicle Registration Certificate (RC) validity via the MoRTH
-- Parivahan API.
--
-- The caller must populate the optional fields @engineNumber@ and
-- @chassisNumber@ in 'InterfaceTypes.VerifyRCReq'; if either or both are
-- absent a 'MorthError' (HTTP 400) is thrown with one of the error codes
-- @ENGINE_NUMBER_REQUIRED@, @CHASSIS_NUMBER_REQUIRED@, or
-- @ENGINE_NUMBER_AND_CHASSIS_NUMBER_REQUIRED@ so that the UI can surface the
-- error and prompt the user to supply the missing values.
verifyRCAsync ::
( EncFlow m r,
CoreMetrics m,
HasRequestId r,
MonadReader r m
) =>
MorthVerificationCfg ->
InterfaceTypes.VerifyRCReq ->
m InterfaceTypes.VerifyRCResp
verifyRCAsync cfg req = do
let missingEngNo = isNothing req.engineNumber
missingChasiNo = isNothing req.chassisNumber
when (missingEngNo && missingChasiNo) $
throwError MorthEngineAndChassisNumberRequired
engNo <- req.engineNumber & maybe (throwError MorthEngineNumberRequired) pure
chasiNo <- req.chassisNumber & maybe (throwError MorthChassisNumberRequired) pure
let morthReq = makeMorthReq req engNo chasiNo
resp <- MorthFlow.getVehicleBasicInfo cfg morthReq
let rcResp = convertToRCVerificationResponse req resp
return $
InterfaceTypes.SyncResp
InterfaceTypes.VerifySyncResp
{ requestId = Nothing,
requestor = VT.Morth,
transactionId = Nothing,
response = rcResp
}
where
makeMorthReq :: InterfaceTypes.VerifyRCReq -> Text -> Text -> VehicleBasicInfoReq
makeMorthReq InterfaceTypes.VerifyRCReq {..} engNo chasiNo =
VehicleBasicInfoReq
{ regnNo = rcNumber,
applicantMobile = fromMaybe "" applicantMobile,
engNo = engNo,
chasiNo = chasiNo
}

-- Convert the MoRTH getVehicleBasicInfo response into the common 'VT.RCVerificationResponse'.
convertToRCVerificationResponse :: InterfaceTypes.VerifyRCReq -> VehicleBasicInfoResp -> VT.RCVerificationResponse
convertToRCVerificationResponse InterfaceTypes.VerifyRCReq {..} VehicleBasicInfoResp {..} =
VT.RCVerificationResponse
{ registrationDate = Nothing,
registrationNumber = Just rcNumber,
fitnessUpto = Nothing,
insuranceValidity = Nothing,
vehicleClass = data_ >>= (.vehcileCatg), -- vehcileClass is coming in code form the MoRTH API
vehicleCategory = data_ >>= (.vehcileCatg),
seatingCapacity = Nothing,
manufacturer = data_ >>= (.maker),
permitValidityFrom = Nothing,
permitValidityUpto = Nothing,
pucValidityUpto = Nothing,
manufacturerModel = data_ >>= (.model),
mYManufacturing = Nothing,
color = data_ >>= (.color),
fuelType = Nothing,
bodyType = Nothing,
status = if success then Just "VALID" else Nothing,
grossVehicleWeight = Nothing,
unladdenWeight = Nothing
}
Loading
Loading