Implement payment request creation functions.
[?]
Feb 20, 2017, 6:16 PM
SEWTRB6S5PO5MQBLCPVBD7XT2BDYNZUE2RO6Z2XENZRIOCN6OZJACDependencies
- [2]
HMDM3B55Implement core of payments/billing infrastructure. - [3]
64C6AWH6Rename Ananke -> Quixotic, project reboot. - [4]
WAIX6AGNAdd event serialization for PaymentRequest & Payment - [5]
Q5X5RYQLstylish-haskell reformatting - [6]
4IQVQL4TAdded client for payouts endpoint. - [7]
5XFJNUAZStart of addition of project infrastructure. - [8]
GCVQD44VCreate amends endpoint, switch to UUID primary keys - [9]
PBD7LZYQPostgres & auth are beginning to function. - [10]
NAS4BFL4Trivial stylish-haskell reformat. - [11]
NLZ3JXLOFix formatting with stylish-haskell. - [12]
TNR3TEHKSwitch to Postgres + snaplet arch compiles. - [13]
2G3GNDDUEvent logging is now functioning in postgres. - [14]
WFZDMVUXRename ADB -> QDB - [15]
73NDXDEZBegin implementation of billing event persistence. - [16]
7HPY3QPFFix linting errors. (yay hlint!) - [17]
KEP5WUFJConvert project to stack-based build. - [18]
Z7KS5XHHVery WIP. Wow. - [19]
4U7F3CPITHE GREAT RENAMING OF THINGS! - [20]
W35DDBFYFactor common JSON conversions up into client lib module. - [21]
LD4GLVSFMore database stuff. - [22]
2XQD6KKKAdd invitation logic and clean up DBProg error handling. - [23]
IZEVQF62Work in progress replacing sqlite with postgres. - [24]
DFOBMSAOInitial work on payments API - [25]
Z3MK2PJ5Add GET handler for retrieving auction data. - [26]
NEDDHXUKReformat via stylish-haskell - [27]
5OI44E4EAdd authentication to auction search. - [28]
Y3LIJ5USAdd handler for CreatePaymentRequest - [29]
QADKFHARAdds CreatePayment handler implementation. - [30]
O227CEAVAdds storage of original event JSON for some DBOp constructors. - [31]
A6HKMINBAttempting to improve JSON handling. - [32]
XTBSG4C7Adding serveJSON combinator to eliminate some boilerplate from handlers. - [33]
FD7SV5I6Fix handling of event_t columns. - [34]
O5FVTOM6Undo JSON silliness, enable a couple more routes. - [35]
HALRDT2FAdded initial auction create route. - [36]
EKY7U7SKFinish conversion to stack. - [37]
QMRKFEPGRefactor QDB to use a free monad algebra instead. - [38]
M4KM76DGMerge branch 'stackify' - [39]
ZP62WC47Begin conversion to build with stack. - [40]
NTPC7KJETrivial changes, feature scratchpad. - [*]
BWN72T44Don't accept work timestamp from an external source. - [*]
RN7EI6INUpdate database layer to use CreditTo
Change contents
- edit in aftok.cabal at line 34
Aftok.Time - edit in aftok.cabal at line 72
, transformers - file deletion: Time.hs
{-# LANGUAGE TemplateHaskell #-}module Aftok.Time whereimport ClassyPreludenewtype Days = Days IntmakePrisms ''Daysimport Control.Lens (makePrisms) - replacement in lib/Aftok/Billables.hs at line 10
import Control.Lens (makeLenses, makePrisms)import Control.Lens (makeLenses, makePrisms, preview, view, _Just)import Data.List (unfoldr)import Data.Thyme.Time as T - edit in lib/Aftok/Billables.hs at line 18
import Aftok.Time (Days (..)) - replacement in lib/Aftok/Billables.hs at line 25
| Monthly Int| SemiMonthly| Monthly T.Months-- | SemiMonthly - replacement in lib/Aftok/Billables.hs at line 34
recurrenceName SemiMonthly = "semimonthly"--recurrenceName SemiMonthly = "semimonthly" - replacement in lib/Aftok/Billables.hs at line 41
recurrenceCount SemiMonthly = Nothing--recurrenceCount SemiMonthly = Nothing - replacement in lib/Aftok/Billables.hs at line 68
, _requestExpiryPeriod :: Maybe C.NominalDiffTime, _requestExpiryPeriod :: Maybe C.NominalDiffTime - replacement in lib/Aftok/Billables.hs at line 77
data Subscription' b = Subscriptiondata Subscription' b = Subscription - edit in lib/Aftok/Billables.hs at line 86[2.1660]
nextRecurrence :: Recurrence -> T.Day -> Maybe T.DaynextRecurrence r = case r ofAnnually -> Just . T.addGregorianYearsClip 1Monthly m -> Just . T.addGregorianMonthsClip mWeekly w -> Just . T.addDays (w * 7)OneTime -> const Nothing{-- A stream of dates upon which the specified subscription- should be billed, beginning with the first day of the- subscription.-}billingSchedule :: Subscription' Billable -> [T.Day]billingSchedule s =let rec = view (billable . recurrence) ssubEndDay = preview (endTime . _Just . C._utctDay) snext :: Maybe T.Day -> Maybe (T.Day, Maybe T.Day)next d = dod' <- dif (all (d' <) subEndDay) then Just (d', nextRecurrence rec d') else Nothingin unfoldr next (Just $ view (startTime . C._utctDay) s) - replacement in lib/Aftok/Database/PostgreSQL.hs at line 11
import Data.List as Limport Data.ProtocolBuffers (encodeMessage)import qualified Data.List as Limport Data.ProtocolBuffers (encodeMessage, decodeMessage)import Data.Serialize.Get (runGet) - replacement in lib/Aftok/Database/PostgreSQL.hs at line 34[3.124]→[3.173:205](∅→∅),[3.162]→[3.173:205](∅→∅),[3.1008]→[3.173:205](∅→∅),[2.1802]→[3.173:205](∅→∅),[3.1678]→[3.173:205](∅→∅)
import Aftok.Paymentsimport Aftok.Payments.Types - edit in lib/Aftok/Database/PostgreSQL.hs at line 36
import Aftok.Time (Days (..), _Days) - replacement in lib/Aftok/Database/PostgreSQL.hs at line 48[3.1216]→[2.1803:1862](∅→∅),[2.1862]→[3.1373:1374](∅→∅),[3.1373]→[3.1373:1374](∅→∅),[3.1374]→[2.1863:1932](∅→∅)
uidParser :: RowParser UserIduidParser = UserId <$> fieldpidParser :: RowParser P.ProjectIdpidParser = P.ProjectId <$> fieldidParser :: (UUID -> a) -> RowParser aidParser f = f <$> field - edit in lib/Aftok/Database/PostgreSQL.hs at line 51
subscriptionIdParser :: RowParser B.SubscriptionIdsubscriptionIdParser = B.SubscriptionId <$> field - replacement in lib/Aftok/Database/PostgreSQL.hs at line 84
parser "credit_to_user" = CreditToUser <$> (nullField *> uidParser <* nullField)parser "credit_to_project" = CreditToProject <$> (nullField *> nullField *> pidParser)parser "credit_to_user" = CreditToUser <$> (nullField *> idParser UserId <* nullField)parser "credit_to_project" = CreditToProject <$> (nullField *> nullField *> idParser P.ProjectId) - replacement in lib/Aftok/Database/PostgreSQL.hs at line 101
(,,) <$> pidParser<*> uidParser(,,) <$> idParser P.ProjectId<*> idParser UserId - replacement in lib/Aftok/Database/PostgreSQL.hs at line 107
A.Auction <$> pidParser<*> uidParserA.Auction <$> idParser P.ProjectId<*> idParser UserId - replacement in lib/Aftok/Database/PostgreSQL.hs at line 116
A.Bid <$> uidParserA.Bid <$> idParser UserId - edit in lib/Aftok/Database/PostgreSQL.hs at line 126[3.1010]→[3.2934:2935](∅→∅),[3.2239]→[3.2934:2935](∅→∅),[3.2934]→[3.2934:2935](∅→∅),[3.2935]→[3.384:421](∅→∅),[3.421]→[3.2161:2177](∅→∅),[3.2177]→[2.2997:3017](∅→∅),[3.2207]→[3.1094:1115](∅→∅),[2.3017]→[3.1094:1115](∅→∅),[3.1094]→[3.1094:1115](∅→∅)
qdbUserParser :: RowParser KeyedUserqdbUserParser =(,) <$> uidParser<*> userParser - replacement in lib/Aftok/Database/PostgreSQL.hs at line 131
<*> uidParser<*> idParser UserId - replacement in lib/Aftok/Database/PostgreSQL.hs at line 136
P.Invitation <$> pidParser<*> uidParserP.Invitation <$> idParser P.ProjectId<*> idParser UserId - edit in lib/Aftok/Database/PostgreSQL.hs at line 141[3.3457]→[3.2530:2531](∅→∅),[3.2530]→[3.2530:2531](∅→∅),[3.2531]→[3.461:504](∅→∅),[3.314]→[3.461:504](∅→∅),[3.504]→[3.2299:2318](∅→∅),[3.2318]→[2.3195:3215](∅→∅),[3.2348]→[3.1337:1361](∅→∅),[2.3215]→[3.1337:1361](∅→∅),[3.1337]→[3.1337:1361](∅→∅)
qdbProjectParser :: RowParser KeyedProjectqdbProjectParser =(,) <$> pidParser<*> projectParser - replacement in lib/Aftok/Database/PostgreSQL.hs at line 144
B.Billable <$> pidParser<*> uidParserB.Billable <$> idParser P.ProjectId<*> idParser UserId - replacement in lib/Aftok/Database/PostgreSQL.hs at line 150
<*> (Days <$> field)<*> field - replacement in lib/Aftok/Database/PostgreSQL.hs at line 158
prec "semimonthly" = nullField *> pure B.SemiMonthly--prec "semimonthly" = nullField *> pure B.SemiMonthly - replacement in lib/Aftok/Database/PostgreSQL.hs at line 161
prec _ = emptyprec s = fail $ "Unrecognized recurrence type: " ++ show s - edit in lib/Aftok/Database/PostgreSQL.hs at line 169
paymentRequestParser :: RowParser PaymentRequestpaymentRequestParser =PaymentRequest <$> (B.SubscriptionId <$> field)<*> (field >>= (either fail pure . runGet decodeMessage))<*> (toThyme <$> field)<*> (toThyme <$> field)paymentParser :: RowParser PaymentpaymentParser =Payment <$> (PaymentRequestId <$> field)<*> (field >>= (either fail pure . runGet decodeMessage))<*> (toThyme <$> field) - replacement in lib/Aftok/Database/PostgreSQL.hs at line 350
pgEval (ReadBids aucId) =pquery bidParser"SELECT user_id, bid_seconds, bid_amount, bid_time FROM bids WHERE auction_id = ?"pgEval (FindBids aucId) =pquery ((,) <$> idParser A.BidId <*> bidParser)"SELECT id, user_id, bid_seconds, bid_amount, bid_time FROM bids WHERE auction_id = ?" - replacement in lib/Aftok/Database/PostgreSQL.hs at line 371
headMay <$> pquery qdbUserParserheadMay <$> pquery ((,) <$> idParser UserId <*> userParser) - replacement in lib/Aftok/Database/PostgreSQL.hs at line 412
pquery qdbProjectParserpquery ((,) <$> idParser P.ProjectId <*> projectParser) - replacement in lib/Aftok/Database/PostgreSQL.hs at line 437
, b ^. (B.gracePeriod . _Days), b ^. (B.gracePeriod) - replacement in lib/Aftok/Database/PostgreSQL.hs at line 440
pgEval (ReadBillable bid) =pgEval (FindBillable bid) = - edit in lib/Aftok/Database/PostgreSQL.hs at line 455
pgEval (FindSubscription sid) =headMay <$> pquery subscriptionParser"SELECT id, billable_id, start_date, end_date \\FROM subscriptions s \\WHERE s.id = ?"(Only (sid ^. B._SubscriptionId)) - replacement in lib/Aftok/Database/PostgreSQL.hs at line 464
pquery ((,) <$> subscriptionIdParser <*> subscriptionParser)pquery ((,) <$> idParser B.SubscriptionId <*> subscriptionParser) - replacement in lib/Aftok/Database/PostgreSQL.hs at line 477
\(subscription_id, event_id, request_data) \\VALUES (?, ?, ?) RETURNING id"\(subscription_id, event_id, request_data, request_time, billing_date) \\VALUES (?, ?, ?, ?, ?) RETURNING id" - edit in lib/Aftok/Database/PostgreSQL.hs at line 482
, req ^. (paymentRequestTime . to fromThyme), req ^. (billingDate . to fromThyme) - replacement in lib/Aftok/Database/PostgreSQL.hs at line 486
pgEval dbop @ (CreatePayment _ req) = dopgEval (FindPaymentRequest rid) =headMay <$> pquery paymentRequestParser"SELECT subscription_id, request_data, request_time, billing_date \\FROM payment_requests \\WHERE id = ?"(Only (rid ^. _PaymentRequestId))pgEval (FindPaymentRequests sid) =pquery ((,) <$> idParser PaymentRequestId <*> paymentRequestParser)"SELECT id, subscription_id, request_data, request_time, billing_date \\FROM payment_requests \\WHERE subscription_id = ?"(Only (sid ^. B._SubscriptionId))pgEval dbop @ (CreatePayment _ p) = do - replacement in lib/Aftok/Database/PostgreSQL.hs at line 504
\(payment_request_id, event_id, payment_data) \\VALUES (?, ?, ?) RETURNING id"( req ^. (request . _PaymentRequestId)\(payment_request_id, event_id, payment_data, payment_date) \\VALUES (?, ?, ?, ?) RETURNING id"( p ^. (request . _PaymentRequestId) - replacement in lib/Aftok/Database/PostgreSQL.hs at line 508
, req ^. (payment . to (runPut . encodeMessage)), p ^. (payment . to (runPut . encodeMessage)), p ^. (paymentDate . to fromThyme) - edit in lib/Aftok/Database/PostgreSQL.hs at line 511
pgEval (FindPayments rid) =pquery ((,) <$> idParser PaymentId <*> paymentParser)"SELECT id, payment_request_id, payment_data, payment_date \\FROM payments \\WHERE payment_request_id = ?"(Only (rid ^. _PaymentRequestId)) - edit in lib/Aftok/Database.hs at line 11
import Control.Monad.Trans.Maybe (MaybeT(..)) - edit in lib/Aftok/Database.hs at line 24
type KeyedUser = (UserId, User) - edit in lib/Aftok/Database.hs at line 25
type KeyedProject = (ProjectId, Project) - replacement in lib/Aftok/Database.hs at line 31
FindUserByName :: UserName -> DBOp (Maybe KeyedUser)FindUserByName :: UserName -> DBOp (Maybe (UserId, User)) - replacement in lib/Aftok/Database.hs at line 35
FindUserProjects :: UserId -> DBOp [KeyedProject]FindUserProjects :: UserId -> DBOp [(ProjectId, Project)] - replacement in lib/Aftok/Database.hs at line 50
ReadBids :: AuctionId -> DBOp [Bid]FindBids :: AuctionId -> DBOp [(BidId, Bid)] - replacement in lib/Aftok/Database.hs at line 53
ReadBillable :: BillableId -> DBOp (Maybe Billable)FindBillable :: BillableId -> DBOp (Maybe Billable) - edit in lib/Aftok/Database.hs at line 56
FindSubscription :: SubscriptionId -> DBOp (Maybe Subscription) - replacement in lib/Aftok/Database.hs at line 59
CreatePaymentRequest :: UserId -> PaymentRequest -> DBOp PaymentRequestIdCreatePayment :: UserId -> Payment -> DBOp PaymentIdCreatePaymentRequest :: UserId -> PaymentRequest -> DBOp PaymentRequestIdFindPaymentRequest :: PaymentRequestId -> DBOp (Maybe PaymentRequest)FindPaymentRequests :: SubscriptionId -> DBOp [(PaymentRequestId, PaymentRequest)]CreatePayment :: UserId -> Payment -> DBOp PaymentIdFindPayments :: PaymentRequestId -> DBOp [(PaymentId, Payment)] - replacement in lib/Aftok/Database.hs at line 102
findUserByName :: (MonadDB m) => UserName -> m (Maybe KeyedUser)findUserByName :: (MonadDB m) => UserName -> m (Maybe (UserId, User)) - replacement in lib/Aftok/Database.hs at line 118
findUserProjects :: (MonadDB m) => UserId -> m [KeyedProject]findUserProjects :: (MonadDB m) => UserId -> m [(ProjectId, Project)] - replacement in lib/Aftok/Database.hs at line 189
readBillable :: (MonadDB m) => BillableId -> m (Maybe Billable)readBillable = liftdb . ReadBillablefindBillable :: (MonadDB m) => BillableId -> MaybeT m BillablefindBillable = MaybeT . liftdb . FindBillablefindSubscriptions :: (MonadDB m) => UserId -> ProjectId -> m [(SubscriptionId, Subscription)]findSubscriptions uid pid = liftdb $ FindSubscriptions uid pidfindSubscriptionBillable :: (MonadDB m) => SubscriptionId -> MaybeT m (Subscription' Billable)findSubscriptionBillable sid = dosub <- MaybeT . liftdb $ FindSubscription sidtraverse findBillable sub - replacement in lib/Aftok/Database.hs at line 200
findSubscriptions :: (MonadDB m)=> UserId-> ProjectId-> m [(SubscriptionId, Subscription' Billable)]findSubscriptions uid pid = dosubscriptions <- liftdb $ FindSubscriptions uid pidlet sub'' s = sequenceA <$> traverse readBillable ssub' (sid, s) = fmap (fmap (sid,)) (sub'' s)catMaybes <$> traverse sub' subscriptionsfindPaymentRequests :: (MonadDB m) => SubscriptionId -> m [(PaymentRequestId, PaymentRequest)]findPaymentRequests = liftdb . FindPaymentRequests - replacement in lib/Aftok/Database.hs at line 203[3.1595]→[2.9536:9595](∅→∅),[3.515]→[3.4861:4910](∅→∅),[2.9595]→[3.4861:4910](∅→∅),[3.13896]→[3.4861:4910](∅→∅),[3.4861]→[3.4861:4910](∅→∅)
readPaymentHistory :: (MonadDB m) => UserId -> m [Payment]readPaymentHistory = error "Not yet implemented"findPayment :: (MonadDB m) => PaymentRequestId -> m (Maybe Payment)findPayment prid = (fmap snd . headMay) <$> liftdb (FindPayments prid) - edit in lib/Aftok/Json.hs at line 24[42.58][43.3094]
import Data.Thyme.Calendar (showGregorian) - edit in lib/Aftok/Json.hs at line 30
import Aftok.Database - edit in lib/Aftok/Json.hs at line 33
import Aftok.Time - replacement in lib/Aftok/Json.hs at line 102
qdbProjectJSON :: KeyedProject -> ValueqdbProjectJSON :: (ProjectId, Project) -> Value - replacement in lib/Aftok/Json.hs at line 181
, "gracePeriod" .= (b ^. (B.gracePeriod . _Days)), "gracePeriod" .= (b ^. B.gracePeriod) - replacement in lib/Aftok/Json.hs at line 188
recurrenceJSON' B.SemiMonthly = object [ "semimonthly" .= Null ]--recurrenceJSON' B.SemiMonthly = object [ "semimonthly" .= Null ] - replacement in lib/Aftok/Json.hs at line 202
, "payment_request_date" .= (r ^. paymentRequestDate), "payment_request_time" .= (r ^. paymentRequestTime), "billing_date" .= (r ^. (billingDate . to showGregorian)) - edit in lib/Aftok/Payments/Types.hs at line 2
{-# LANGUAGE DeriveFunctor #-}{-# LANGUAGE DeriveFoldable #-}{-# LANGUAGE DeriveTraversable #-} - edit in lib/Aftok/Payments/Types.hs at line 12
import Data.Thyme.Time as T - edit in lib/Aftok/Payments/Types.hs at line 16
import Network.Bippy.Types (expiryTime, getPaymentDetails, getExpires) - replacement in lib/Aftok/Payments/Types.hs at line 30
, _paymentRequestDate :: C.UTCTime}, _paymentRequestTime :: C.UTCTime, _billingDate :: T.Day} deriving (Functor, Foldable, Traversable) - replacement in lib/Aftok/Payments/Types.hs at line 41
}} deriving (Functor, Foldable, Traversable) - replacement in lib/Aftok/Payments/Types.hs at line 46[2.11452]
{- Check whether the specified payment request has expired (whether wallet software- will still consider the payment request valid)-}isExpired :: C.UTCTime -> P.PaymentRequest -> BoolisExpired now req =let check = any ((now >) . T.toThyme . expiryTime)-- using error here is reasonable since it would indicate-- a serialization problemin either error (check . getExpires) $ getPaymentDetails req - replacement in lib/Aftok/Payments.hs at line 11
import Control.Lens (makeLenses, view, (%~), (^.))import Control.Error.Util (maybeT)import Control.Lens (makeClassy, makeClassyPrisms, view, (%~), (^.), review) - replacement in lib/Aftok/Payments.hs at line 14
import Control.Monad.Except (MonadError)import Crypto.PubKey.RSA.Types (Error(..), PrivateKey)import Control.Monad.Except (MonadError, throwError)import qualified Crypto.PubKey.RSA.Types as RSA (Error(..), PrivateKey) - edit in lib/Aftok/Payments.hs at line 20
import Data.Thyme.Time as T - edit in lib/Aftok/Payments.hs at line 22
import Data.Thyme.Time.Core (fromThyme) - replacement in lib/Aftok/Payments.hs at line 39
, _signingKey :: PrivateKey, _signingKey :: RSA.PrivateKey - replacement in lib/Aftok/Payments.hs at line 42
makeLenses ''BillingConfigmakeClassy ''BillingConfigdata BillingOps (m :: * -> *) = BillingOps{ memoGen :: Subscription' Billable -> m (Maybe Text) -- ^ generator user memo, uriGen :: Subscription' Billable -> m (Maybe URI) -- ^ generator for payment response URL, payloadGen :: Subscription' Billable -> m (Maybe ByteString) -- ^ generator for merchant payload}data PaymentRequestStatus= Paid Payment -- ^ the request was paid with the specified payment| Unpaid PaymentRequest -- ^ the request has not been paid, but has not yet expired| Expired PaymentRequest -- ^ the request was not paid prior to the expiration date - edit in lib/Aftok/Payments.hs at line 55
data PaymentError= Overdue SubscriptionId| SigningError RSA.ErrormakeClassyPrisms ''PaymentError - replacement in lib/Aftok/Payments.hs at line 61
createPaymentRequests :: (MonadRandom m, MonadReader BillingConfig m, MonadError Error m, MonadDB m) =>C.UTCTime -- timestamp for payment request creation-> (Subscription' Billable -> m (Maybe Text)) -- generator user memo-> (Subscription' Billable -> m (Maybe URI)) -- generator for payment response URL-> (Subscription' Billable -> m (Maybe ByteString)) -- generator for merchant payload-> UserId -- user responsible for payment-> ProjectId -- project whose worklog is to be paid out tocreatePaymentRequests :: ( MonadRandom m, MonadReader r m, HasBillingConfig r, MonadError e m, AsPaymentError e, MonadDB m)=> BillingOps m -- ^ generators for payment request components-> C.UTCTime -- ^ timestamp for payment request creation-> UserId -- ^ customer responsible for payment-> ProjectId -- ^ project whose worklog is to be paid - replacement in lib/Aftok/Payments.hs at line 71
createPaymentRequests t memogen urigen plgen custId pid = docreatePaymentRequests ops now custId pid = do - edit in lib/Aftok/Payments.hs at line 73
join <$> traverse (createSubscriptionPaymentRequests ops now custId) subscriptionscreateSubscriptionPaymentRequests ::( MonadRandom m, MonadReader r m, HasBillingConfig r, MonadError e m, AsPaymentError e, MonadDB m)=> BillingOps m-> C.UTCTime-> UserId-> (SubscriptionId, Subscription)-> m [PaymentRequestId]createSubscriptionPaymentRequests ops now custId (sid, sub) = dobillableSub <- maybeT (raiseSubjectNotFound . FindBillable $ sub ^. billable) pure $traverse findBillable subpaymentRequests <- findPaymentRequests sidbillableDates <- findUnbilledDates now (view billable billableSub) paymentRequests $takeWhile (< view _utctDay now) $ billingSchedule billableSubtraverse (createPaymentRequest ops now custId sid billableSub) billableDatescreatePaymentRequest ::( MonadRandom m, MonadReader r m, HasBillingConfig r, MonadError e m, AsPaymentError e, MonadDB m)=> BillingOps m-> C.UTCTime-> UserId-> SubscriptionId-> Subscription' Billable-> T.Day-> m PaymentRequestIdcreatePaymentRequest ops now custId sid sub bday = do - replacement in lib/Aftok/Payments.hs at line 109
let createPaymentDetails' s = domemo <- memogen suri <- urigen spayload <- plgen screatePaymentDetails t memo uri payload (s ^. billable)memo <- memoGen ops suburi <- uriGen ops subpayload <- payloadGen ops subdetails <- createPaymentDetails bday now memo uri payload (sub ^. billable)reqErr <- B.createPaymentRequest (cfg ^. signingKey) (cfg ^. pkiData) detailsreq <- either (throwError . review _SigningError) pure reqErrliftdb $ CreatePaymentRequest custId (PaymentRequest sid req now bday){-- FIXME: The current implementation expects the billing day to be a suitable- key for comparison to payment requests. This is almost certainly inadequate.-}findUnbilledDates :: (MonadDB m, MonadError e m, AsPaymentError e)=> C.UTCTime -- ^ the date against which payment request expiration should be checked-> Billable-> [(PaymentRequestId, PaymentRequest)] -- ^ the list of existing payment requests-> [T.Day] -- ^ the list of expected billing days-> m [T.Day] -- ^ the list of billing days for which no payment request existsfindUnbilledDates now b (px @ (p : ps)) (dx @ (d : ds)) =case compare (view (_2 . billingDate) p) d ofEQ -> getRequestStatus now p >>= \s -> case s ofExpired r -> if view _utctDay now > addDays (view gracePeriod b) (view billingDate r)then throwError (review _Overdue (r ^. subscription))else fmap (d :) $ findUnbilledDates now b px dx -- d will be rebilled_ -> findUnbilledDates now b ps ds -- if paid or unpaid, nothing to doGT -> fmap (d :) $ findUnbilledDates now b px dsLT -> findUnbilledDates now b ps dxfindUnbilledDates _ _ _ ds = pure ds - replacement in lib/Aftok/Payments.hs at line 138
createPaymentRequest (sid, s) = dodetails <- createPaymentDetails' sreq <- B.createPaymentRequest (cfg ^. signingKey) (cfg ^. pkiData) detailsliftdb $ CreatePaymentRequest custId (PaymentRequest sid req t)traverse createPaymentRequest subscriptions{- Check whether the specified payment request has a payment associated with- it, and return a PaymentRequestStatus value indicating the result.-}getRequestStatus :: (MonadDB m)=> C.UTCTime -- ^ the date against which request expiration should be checked-> (PaymentRequestId, PaymentRequest) -- ^ the request for which to find a payment-> m PaymentRequestStatusgetRequestStatus now (reqid, req) =let ifUnpaid = (if isExpired now (view paymentRequest req) then Expired else Unpaid) reqin maybe ifUnpaid Paid <$> findPayment reqid - replacement in lib/Aftok/Payments.hs at line 150
createPaymentDetails :: (MonadRandom m, MonadReader BillingConfig m, MonadDB m) =>C.UTCTime -- timestamp for payment request creation-> Maybe Text -- user memo-> Maybe URI -- payment response URL-> Maybe ByteString -- merchant payload-> Billable{- Create the PaymentDetails section of the payment request.-}createPaymentDetails :: (MonadRandom m, MonadReader r m, HasBillingConfig r, MonadDB m)=> T.Day -- ^ payout date (billing date)-> C.UTCTime -- ^ timestamp of payment request creation-> Maybe Text -- ^ user memo-> Maybe URI -- ^ payment response URL-> Maybe ByteString -- ^ merchant payload-> Billable -- ^ billing information - replacement in lib/Aftok/Payments.hs at line 160
createPaymentDetails t memo uri payload b = dopayouts <- getProjectPayouts t (b ^. project)outputs <- createPayoutsOutputs t (b ^. amount) payoutslet expiry = (BT.Expiry . fromThyme . (t .+^)) <$> (b ^. requestExpiryPeriod)createPaymentDetails payoutDate billingTime memo uri payload b = dopayouts <- getProjectPayouts payoutTime (b ^. project)outputs <- createPayoutsOutputs payoutTime (b ^. amount) payoutslet expiry = (BT.Expiry . T.fromThyme . (billingTime .+^)) <$> (b ^. requestExpiryPeriod) - replacement in lib/Aftok/Payments.hs at line 165
pure $ B.createPaymentDetails (cfg ^. network) outputs (fromThyme t) expiry memo uri payloadpure $ B.createPaymentDetails(cfg ^. network)outputs(T.fromThyme billingTime)expiry memo uri payloadwherepayoutTime = T.mkUTCTime payoutDate (fromInteger 0) - replacement in server/Aftok/Snaplet/Projects.hs at line 46
projectListHandler :: S.Handler App App [KeyedProject]projectListHandler :: S.Handler App App [(ProjectId, Project)] - replacement in stack.yaml at line 6
commit: ddfc1bf0911351d0be51f33ea9e4166a24d2b19acommit: 97fda0368ae660239d1b9398d44530cd5b05eec3