core, badge service: share one store transaction reference, and mark a verified transaction as such

This commit is contained in:
spaced4ndy
2026-10-01 15:53:20 +04:00
parent 6df330e232
commit dc392994bf
11 changed files with 93 additions and 80 deletions
+3 -2
View File
@@ -77,6 +77,7 @@ import Simplex.Chat.Messages.CIContent.Events
import Simplex.Chat.Operators
import Simplex.Chat.Options
import Simplex.Chat.PaymentService (ServicePayment (..), appleTransactionId, googlePurchaseRef)
import Simplex.Chat.PaymentService.Types (PaymentProvider (..), StoreTransactionRef (..))
import Simplex.Chat.ProfileGenerator (generateRandomProfile)
import Simplex.Chat.Protocol
import Simplex.Chat.Remote
@@ -5280,8 +5281,8 @@ purchaseBadge nm presentingUser echoedInvoiceId payment = do
-- | The same reference the service claims a transaction by, read without verifying anything.
storeTransactionRef :: ServicePayment -> Maybe StoreTransactionRef
storeTransactionRef = \case
SPApple {jws} -> StoreTransactionRef "apple" <$> appleTransactionId jws
SPGoogle {token} -> Just $ StoreTransactionRef "google" $ googlePurchaseRef token
SPApple {jws} -> StoreTransactionRef PPApple <$> appleTransactionId jws
SPGoogle {token} -> Just $ StoreTransactionRef PPGoogle $ googlePurchaseRef token
SPInvoice {} -> Nothing
SPReceipt {} -> Nothing
+40
View File
@@ -1,6 +1,9 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
module Simplex.Chat.PaymentService.Types
@@ -8,6 +11,7 @@ module Simplex.Chat.PaymentService.Types
InvoiceId (..),
PaymentId (..),
PaymentProvider (..),
StoreTransactionRef (..),
CardProvider (..),
CryptoCurrency (..),
ServicePaymentMethod (..),
@@ -26,7 +30,16 @@ import Data.ByteString.Char8 (ByteString)
import Data.Text (Text)
import Data.Time.Clock (UTCTime)
import Data.Word (Word32)
import Simplex.Messaging.Agent.Store.DB (fromTextField_)
import Simplex.Messaging.Encoding.String (TextEncoding (..))
import Simplex.Messaging.Parsers (dropPrefix, enumJSON, taggedObjectJSON)
#if defined(dbPostgres)
import Database.PostgreSQL.Simple.FromField (FromField (..))
import Database.PostgreSQL.Simple.ToField (ToField (..))
#else
import Database.SQLite.Simple.FromField (FromField (..))
import Database.SQLite.Simple.ToField (ToField (..))
#endif
-- USD etc. are in minor units, following Stripe etc. convention
newtype CurrencyAmount = CurrencyAmount Word32
@@ -45,6 +58,32 @@ newtype PaymentId = PaymentId Text
data PaymentProvider = PPApple | PPGoogle | PPStripe | PPCrypto | PPCode | PPReceipt
deriving (Eq, Show)
instance TextEncoding PaymentProvider where
textEncode = \case
PPApple -> "apple"
PPGoogle -> "google"
PPStripe -> "stripe"
PPCrypto -> "crypto"
PPCode -> "code"
PPReceipt -> "receipt"
textDecode = \case
"apple" -> Just PPApple
"google" -> Just PPGoogle
"stripe" -> Just PPStripe
"crypto" -> Just PPCrypto
"code" -> Just PPCode
"receipt" -> Just PPReceipt
_ -> Nothing
instance FromField PaymentProvider where fromField = fromTextField_ textDecode
instance ToField PaymentProvider where toField = toField . textEncode
-- | A store and its own id for one transaction. The evidence is not the key: the store may sign it
-- again, and a retry of the same purchase has to find the same stash.
data StoreTransactionRef = StoreTransactionRef {provider :: PaymentProvider, transactionRef :: Text}
deriving (Eq, Show)
data CardProvider = CPStripe
deriving (Eq, Show)
@@ -100,6 +139,7 @@ data StoredPayment = StoredPayment
deriving (Show)
-- to review
-- PFApple and PFGoogle hold much what the service's VerifiedStoreTransaction does; the two are reconciled when this is built out.
data PaymentFunding
= PFInvoice
{ invoiceId :: InvoiceId,
+1 -6
View File
@@ -9,7 +9,6 @@
module Simplex.Chat.Store.Badges
( BadgeStash (..),
BadgeStashRef (..),
StoreTransactionRef (..),
UserBadgePurchase (..),
getUserBadgePurchase,
getBadgePurchase,
@@ -52,6 +51,7 @@ import Simplex.Chat.Badges
import Simplex.Chat.Badges.Ledger
import Simplex.Chat.Badges.Service (StatementCreditType (..), StatementDebitType (..), StatementEntry (..), StatementEntryType (..))
import Simplex.Chat.Badges.Types (BadgeAlertKind, BadgeIssueError (..), BadgeIssueFailure, BadgePurchaseStatus (..), OpenStorePurchase (..))
import Simplex.Chat.PaymentService.Types (StoreTransactionRef (..))
import Simplex.Chat.Store.Shared (insertedRowId)
import Simplex.Chat.Types
import Simplex.Messaging.Agent.Protocol (UserId)
@@ -80,11 +80,6 @@ data BadgeStash = BadgeStash
data BadgeStashRef = BSRCodeRedemption Int64 | BSRStoreReceipt Int64
-- | A store and its own id for one transaction. The evidence is not the key: the store may sign it
-- again, and a retry of the same purchase has to find the same stash.
data StoreTransactionRef = StoreTransactionRef {provider :: Text, transactionRef :: Text}
deriving (Eq, Show)
getBadgeCodeRedemption :: DB.Connection -> User -> Text -> IO (Maybe BadgeStash)
getBadgeCodeRedemption db User {userId} code =
maybeFirstRow (toBadgeStash BSRCodeRedemption) $