module Network.PayPal.Types (
Security(..),
Credentials(..),
Status(..),
ToText(..),
FromText(..),
ToVariables(..),
FromVariables(..),
PayPalRequest(decodeResponse, type PayPalResponse),
decodeResponseChecking,
toTextTime,
fromTextTime
) where
import Control.Applicative
import qualified Data.ByteString.Char8 as C
import Data.Map (Map)
import qualified Data.Map as M
import Data.Monoid
import Data.Ratio
import Data.Time.Calendar (Day(..))
import Data.Time.Clock
import Data.Time.Format
import Data.Time.LocalTime (TimeOfDay(..))
import System.Locale (defaultTimeLocale)
import Numeric
data Security = Signature C.ByteString
data Credentials = Credentials {
crUsername :: C.ByteString,
crPassword :: C.ByteString,
crSecurity :: Security,
crVersion :: C.ByteString
}
decodeResponseChecking :: PayPalRequest req =>
[(C.ByteString, C.ByteString)]
-> Status (PayPalResponse req)
decodeResponseChecking pairs =
case "ACK" `M.lookup` m of
Just "Success" -> decodeResponse m
Just "Failure" -> case messages 0 of
[] -> noParse
msgs -> Failure msgs
_ -> noParse
where
m = M.fromList pairs
noParse = ParseFailure (M.toList m) $ "malformed error message"
messages i = case (`M.lookup` m) . (`mappend` si) <$>
["L_ERRORCODE", "L_SHORTMESSAGE", "L_LONGMESSAGE", "L_SEVERITYCODE"] of
[Just err, Just short, Just long, Just severity] ->
case reads (C.unpack err) of
[(errNo, "")] -> Message errNo short long severity : messages (i+1)
_ -> []
_ -> []
where
si = C.pack (show i)
data Status res = Success res
| Failure [Message]
| ParseFailure [(C.ByteString, C.ByteString)] String
deriving Show
instance Functor Status where
f `fmap` Success res = Success (f res)
f `fmap` Failure msgs = Failure msgs
f `fmap` ParseFailure pairs descr = ParseFailure pairs descr
data Message = Message Int C.ByteString C.ByteString C.ByteString
deriving Show
class ToText a where
toText :: a -> C.ByteString
class FromText a where
fromText :: C.ByteString -> Maybe a
class ToVariables a where
toVariables :: a -> [(C.ByteString, C.ByteString)]
class FromVariables a where
fromVariables :: Map C.ByteString C.ByteString -> Either String a
class ToVariables req => PayPalRequest req where
data PayPalResponse req :: *
decodeResponse :: Map C.ByteString C.ByteString -> Status (PayPalResponse req)
instance ToText Double where
toText dbl = C.pack $ showFFloat Nothing dbl ""
instance FromText Double where
fromText txt = case reads (C.unpack txt) of
[(amt, "")] -> Just amt
_ -> Nothing
instance ToText Int where
toText = C.pack . show
instance FromText Int where
fromText txt = case reads (C.unpack txt) of
[(amt, "")] -> Just amt
_ -> Nothing
instance ToText (Ratio Integer) where
toText amt = C.pack $ showFFloat (Just 2) (realToFrac amt) ""
instance FromText (Ratio Integer) where
fromText txt = case reads (C.unpack txt) of
[(amt, "")] -> Just $ round ((amt :: Double) * 100) % 100
_ -> Nothing
defaultTimeFormat :: String
defaultTimeFormat = "%Y-%m-%dT%H:%M:%SZ"
toTextTime :: FormatTime t => t -> C.ByteString
toTextTime = C.pack . formatTime defaultTimeLocale defaultTimeFormat
fromTextTime :: ParseTime t => C.ByteString -> Maybe t
fromTextTime = parseTime defaultTimeLocale defaultTimeFormat . C.unpack