Created
June 22, 2016 23:22
-
-
Save yreynhout/535a0b9f5960e568659af8e6284b7fcc to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
open System | |
module PlayerAccount = | |
//PlayerWasInvited | |
//PlayerAcceptedInvitation | |
//PlayerRejectedInvitation | |
//PlayerInvitationWasCancelled | |
// | |
type ProfessionalOccupation = Employee | Independent | Labourer | Other | |
type SignUpDocument = { | |
DocumentId: Guid; | |
PlayerId: Guid; | |
NickName: string; | |
InitialPasswordHash: string; | |
InitialPasswordSalt: string; | |
EmailAddress: string; | |
FirstName: string; | |
LastName: string; | |
PlaceOfBirth: string; | |
ProfessionalOccupation: ProfessionalOccupation; | |
OtherProfessionalOccuptation: string option; | |
HasBelgianIdentityCard: bool; | |
BelgianNationalNumber: string option; | |
} | |
type PlayerSignedUp = { PlayerId: Guid; SignUpDocumentId: Guid; NickName: string; EmailAddress: string; At: int64 } | |
type PlayersIdentityConfirmed = { PlayerId: Guid; VerificationDocumentId: Guid; At: int64 } | |
module PlayerWallet = | |
type GiveWalletToPlayer = { WalletId: Guid; PlayerId: Guid; At: int64 } | |
type PutMoneyInPlayersWallet = { WalletId: Guid; Amount: decimal; At: int64 } | |
type PutBonusMoneyInPlayersWallet = { WalletId: Guid; Amount: decimal; Until: int64; At: int64 } | |
type TakeMoneyOutOfPlayersWallet = { WalletId: Guid; Amount: decimal; At: int64 } | |
type TradePlayersWallet = { OldWalletId: Guid; NewWalletId: Guid; At: int64 } | |
type Commands = | |
| GiveWalletToPlayer of GiveWalletToPlayer | |
| PutMoneyInPlayersWallet of PutMoneyInPlayersWallet | |
| PutBonusMoneyInPlayersWallet of PutBonusMoneyInPlayersWallet | |
| TakeMoneyOutOfPlayersWallet of TakeMoneyOutOfPlayersWallet | |
| TradePlayersWallet of TradePlayersWallet | |
type WalletWasGivenToPlayer = { WalletId: Guid; PlayerId: Guid; At: int64 } | |
type MoneyWasPutInPlayersWallet = { WalletId: Guid; PlayerId: Guid; Amount: decimal; At: int64 } | |
type BonusMoneyWasPutInPlayersWallet = { WalletId: Guid; PlayerId: Guid; Amount: decimal; Until: int64; At: int64 } | |
type MoneyWasTakenOutOfPlayersWallet = { WalletId: Guid; PlayerId: Guid; Amount: decimal; At: int64 } | |
type PlayersWalletWasTraded = { OldWalletId: Guid; PlayerId: Guid; NewWalletId: Guid; Balance: decimal; At: int64 } | |
type Events = | |
| WalletWasGivenToPlayer of WalletWasGivenToPlayer | |
| MoneyWasPutInPlayersWallet of MoneyWasPutInPlayersWallet | |
| BonusMoneyWasPutInPlayersWallet of BonusMoneyWasPutInPlayersWallet | |
| MoneyWasTakenOutOfPlayersWallet of MoneyWasTakenOutOfPlayersWallet | |
| PlayersWalletWasTraded of PlayersWalletWasTraded | |
type Conflict = | |
| PlayerHasAlreadyBeenGivenWallet | |
| PlayerWalletMismatch | |
| PlayerWalletHasInsufficientFunds | |
| PlayersWalletAlreadyTraded | |
type PlayerWalletState = { WalletId: Guid; PlayerId: Guid; Balance: decimal; TradedWithWalletId: Guid option } | |
with | |
static member Empty = { WalletId = Guid.Empty; PlayerId = Guid.Empty; Balance = 0.0m; TradedWithWalletId = None } | |
static member Fold (events: Events list) = | |
let folder (state: PlayerWalletState) (event: Events) = | |
match event with | |
| WalletWasGivenToPlayer e -> { state with WalletId = e.WalletId; PlayerId = e.PlayerId; } | |
| MoneyWasPutInPlayersWallet e -> { state with Balance = state.Balance + e.Amount; } | |
| BonusMoneyWasPutInPlayersWallet e -> state | |
| MoneyWasTakenOutOfPlayersWallet e -> { state with Balance = state.Balance - e.Amount; } | |
| PlayersWalletWasTraded e -> { state with TradedWithWalletId = Some e.NewWalletId; } | |
List.fold folder PlayerWalletState.Empty events | |
// A wallet is given to a player just after he signs up and we've confirmed the player's identity, by our system. | |
let giveWallet (command: GiveWalletToPlayer) (state: PlayerWalletState) : Choice<Events list, Conflict> = | |
if state <> PlayerWalletState.Empty then | |
Choice2Of2 PlayerHasAlreadyBeenGivenWallet | |
else | |
//Is this a player we know of? | |
//Is this a new player that does not yet have a wallet? | |
Choice1Of2 [ WalletWasGivenToPlayer { WalletId = command.WalletId; PlayerId = command.PlayerId; At = command.At } ] | |
let putMoney (command: PutMoneyInPlayersWallet) (state: PlayerWalletState) : Choice<Events list, Conflict> = | |
if state.WalletId <> command.WalletId then | |
Choice2Of2 PlayerWalletMismatch | |
else | |
match state.TradedWithWalletId with | |
| Some _ -> Choice2Of2 PlayersWalletAlreadyTraded | |
| None -> Choice1Of2 [ MoneyWasPutInPlayersWallet { WalletId = state.WalletId; PlayerId = state.PlayerId; Amount = command.Amount; At = command.At } ] | |
let takeMoney (command: TakeMoneyOutOfPlayersWallet) (state: PlayerWalletState) : Choice<Events list, Conflict> = | |
if state.WalletId <> command.WalletId then | |
Choice2Of2 PlayerWalletMismatch | |
else | |
match state.TradedWithWalletId with | |
| Some _ -> Choice2Of2 PlayersWalletAlreadyTraded | |
| None -> | |
if state.Balance - command.Amount < 0.0m then | |
Choice2Of2 PlayerWalletHasInsufficientFunds | |
else | |
Choice1Of2 [ MoneyWasTakenOutOfPlayersWallet { WalletId = state.WalletId; PlayerId = state.PlayerId; Amount = command.Amount; At = command.At } ] | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment