diff --git a/lib/mobility-core/src/Kernel/External/Payment/Interface.hs b/lib/mobility-core/src/Kernel/External/Payment/Interface.hs index 228887b4b..434291303 100644 --- a/lib/mobility-core/src/Kernel/External/Payment/Interface.hs +++ b/lib/mobility-core/src/Kernel/External/Payment/Interface.hs @@ -196,6 +196,21 @@ mandateExecution serviceConfig mRoutingId req = case serviceConfig of StripeConfig _ -> throwError $ InternalError "Stripe Mandate Execution not supported." PaytmEDCConfig _ -> throwError $ InternalError "PaytmEDC Mandate Execution not supported." +getMandateStatus :: + ( EncFlow m r, + CoreMetrics m, + HasRequestId r, + MonadReader r m + ) => + PaymentServiceConfig -> + Maybe Text -> + MandateStatusReq -> + m OrderStatusResp +getMandateStatus serviceConfig mRoutingId req = case serviceConfig of + JuspayConfig cfg -> Juspay.getMandateStatus cfg mRoutingId req + StripeConfig _ -> throwError $ InternalError "Stripe Mandate Status not supported." + PaytmEDCConfig _ -> throwError $ InternalError "PaytmEDC Mandate Status not supported." + autoRefunds :: ( EncFlow m r, CoreMetrics m, diff --git a/lib/mobility-core/src/Kernel/External/Payment/Interface/Juspay.hs b/lib/mobility-core/src/Kernel/External/Payment/Interface/Juspay.hs index a61f7fc36..e870a3d5c 100644 --- a/lib/mobility-core/src/Kernel/External/Payment/Interface/Juspay.hs +++ b/lib/mobility-core/src/Kernel/External/Payment/Interface/Juspay.hs @@ -28,6 +28,7 @@ module Kernel.External.Payment.Interface.Juspay mandateRevoke, mandatePause, mandateResume, + getMandateStatus, autoRefund, mandateNotificationStatus, verifyVPA, @@ -582,6 +583,46 @@ mkResumeReq req = resume_date = show $ utcTimeToPOSIXSeconds req.resumeDate } +getMandateStatus :: + ( HasCallStack, + Metrics.CoreMetrics m, + EncFlow m r, + HasRequestId r, + MonadReader r m, + MonadThrow m + ) => + JuspayCfg -> + Maybe Text -> + MandateStatusReq -> + m OrderStatusResp +getMandateStatus config mRoutingId req = do + let url = config.url + merchantId = config.merchantId + apiKey <- decrypt config.apiKey + juspayResp <- Juspay.mandateStatus url apiKey merchantId mRoutingId req.mandateId Juspay.MandateStatusReq {command = "check_status"} + mkMandateStatusRes juspayResp + +mkMandateStatusRes :: (MonadThrow m, Log m) => Juspay.JuspayMandateStatusResp -> m OrderStatusResp +mkMandateStatusRes Juspay.JuspayMandateStatusResp {..} = do + mandateStatusEnum <- (readMaybe (T.unpack status) :: Maybe MandateStatus) & fromMaybeM (InternalError $ "Invalid mandate status: " <> status) + frequencyEnum <- (readMaybe (T.unpack frequency) :: Maybe MandateFrequency) & fromMaybeM (InternalError $ "Invalid mandate frequency: " <> frequency) + startDateUTC <- (posixSecondsToUTCTime <$> (fromIntegral <$> (readMaybe (T.unpack start_date) :: Maybe Int))) & fromMaybeM (InternalError "Invalid start_date format") + endDateUTC <- (posixSecondsToUTCTime <$> (fromIntegral <$> (readMaybe (T.unpack end_date) :: Maybe Int))) & fromMaybeM (InternalError "Invalid end_date format") + return + MandateStatusResp + { eventName = Nothing, + orderShortId = fromMaybe "" order_id, + status = mandateStatusEnum, + mandateStartDate = Just startDateUTC, + mandateEndDate = Just endDateUTC, + mandateId = mandate_id, + mandateFrequency = frequencyEnum, + mandateMaxAmount = realToFrac max_amount, + upi = mkUpi <$> (payment_info >>= (.upi)) + } + where + mkUpi Juspay.MandateUpiInfo {..} = Upi {payerApp = Nothing, payerAppName = Nothing, txnFlowType = Nothing, payerVpa = payer_vpa} + addDaysUtcTime :: UTCTime -> Integer -> UTCTime addDaysUtcTime t x = t {utctDay = addDays x (utctDay t)} diff --git a/lib/mobility-core/src/Kernel/External/Payment/Interface/Types.hs b/lib/mobility-core/src/Kernel/External/Payment/Interface/Types.hs index 5f1732858..7a0cb3b44 100644 --- a/lib/mobility-core/src/Kernel/External/Payment/Interface/Types.hs +++ b/lib/mobility-core/src/Kernel/External/Payment/Interface/Types.hs @@ -435,6 +435,8 @@ data MandatePauseReq = MandatePauseReq {mandateId :: Text, pauseStartDate :: UTC data MandateResumeReq = MandateResumeReq {mandateId :: Text, resumeDate :: UTCTime} +newtype MandateStatusReq = MandateStatusReq {mandateId :: Text} + newtype MandateRevokeReq = MandateRevokeReq {mandateId :: Text} type MandateRevokeRes = APISuccess diff --git a/lib/mobility-core/src/Kernel/External/Payment/Juspay/Flow.hs b/lib/mobility-core/src/Kernel/External/Payment/Juspay/Flow.hs index 823d57f30..a6b4bf5d6 100644 --- a/lib/mobility-core/src/Kernel/External/Payment/Juspay/Flow.hs +++ b/lib/mobility-core/src/Kernel/External/Payment/Juspay/Flow.hs @@ -461,6 +461,38 @@ mandateResume url apiKey mandateId req = do callAPI url (eulerClient mandateId basicAuthData req) "mandate-resume" (Proxy @MandateResumeAPI) >>= fromEitherM (\err -> InternalError $ "Failed to call mandate resume API: " <> show err) +type MandateStatusAPI = + "mandates" + :> Header "x-merchantid" Text + :> Header "x-routing-id" Text + :> BasicAuth "username-password" BasicAuthData + :> Capture "mandateId" Text + :> ReqBody '[FormUrlEncoded] MandateStatusReq + :> Post '[JSON] JuspayMandateStatusResp + +mandateStatus :: + ( Metrics.CoreMetrics m, + MonadFlow m, + HasRequestId r, + MonadReader r m + ) => + BaseUrl -> + Text -> + Text -> + Maybe Text -> + Text -> + MandateStatusReq -> + m JuspayMandateStatusResp +mandateStatus url apiKey merchantId mRoutingId mandateId req = do + let eulerClient = Euler.client (Proxy @MandateStatusAPI) + let basicAuthData = + BasicAuthData + { basicAuthUsername = DT.encodeUtf8 apiKey, + basicAuthPassword = "" + } + callAPI url (eulerClient (Just merchantId) mRoutingId basicAuthData mandateId req) "mandate-status" (Proxy @MandateStatusAPI) + >>= fromEitherM (\err -> InternalError $ "Failed to call mandate status API: " <> show err) + type AutoRefundAPI = "orders" :> Capture "orderId" Text diff --git a/lib/mobility-core/src/Kernel/External/Payment/Juspay/Types/Mandate.hs b/lib/mobility-core/src/Kernel/External/Payment/Juspay/Types/Mandate.hs index 2665be706..38d164c41 100644 --- a/lib/mobility-core/src/Kernel/External/Payment/Juspay/Types/Mandate.hs +++ b/lib/mobility-core/src/Kernel/External/Payment/Juspay/Types/Mandate.hs @@ -148,3 +148,32 @@ data MandateResumeReq = MandateResumeReq resume_date :: Text } deriving (Eq, Show, Generic, ToJSON, FromJSON, ToSchema, ToForm) + +--- For Mandate Status --- + +data MandateStatusReq = MandateStatusReq + { command :: Text + } + deriving (Eq, Show, Generic, ToJSON, FromJSON, ToSchema, ToForm) + +data JuspayMandateStatusResp = JuspayMandateStatusResp + { mandate_id :: Text, + status :: Text, + frequency :: Text, + start_date :: Text, + end_date :: Text, + max_amount :: Double, + order_id :: Maybe Text, + payment_info :: Maybe MandatePaymentInfo + } + deriving (Eq, Show, Generic, ToJSON, FromJSON, ToSchema) + +data MandatePaymentInfo = MandatePaymentInfo + { upi :: Maybe MandateUpiInfo + } + deriving (Eq, Show, Generic, ToJSON, FromJSON, ToSchema) + +data MandateUpiInfo = MandateUpiInfo + { payer_vpa :: Maybe Text + } + deriving (Eq, Show, Generic, ToJSON, FromJSON, ToSchema)