Files
DADProject/api/database/seeders/GamesTransactionsSeeder.php

266 lines
11 KiB
PHP

<?php
namespace Database\Seeders;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class GamesTransactionsSeeder extends Seeder
{
private $faker = null;
private $users = null;
public function run(): void
{
$this->command->info("Create game related Transactions");
$this->faker = \Faker\Factory::create(DatabaseSeeder::$seedLanguage);
$this->users = DB::table('users')->orderBy('id', 'asc')->get();
$games = DB::table('games')->whereNull('match_id')->orderBy('began_at', 'asc')->get();
$matches = DB::table('matches')->orderBy('began_at', 'asc')->get();
$coin_purchases = [];
$coin_transactions = [];
$i = 0;
while($games->count() > 0 || $matches->count() > 0) {
$firstGame = $games->first();
$firstMatch = $matches->first();
$isGameFirst = false;
if ($firstGame && $firstMatch) {
$isGameFirst = $firstGame->began_at < $firstMatch->began_at;
} elseif ($firstGame && !$firstMatch) {
$isGameFirst = true;
} elseif (!$firstGame && $firstMatch) {
$isGameFirst = false;
}
if ($isGameFirst) {
$this->handleGame($coin_purchases, $coin_transactions, $firstGame);
$games->shift();
} else {
$this->handleMatch($coin_purchases, $coin_transactions, $firstMatch);
$matches->shift();
}
$i++;
if ($i >= DatabaseSeeder::$dbInsertBlockSize) {
$this->command->info("Block of coin purchases and transactions");
if (!empty($coin_transactions)) {
DB::table('coin_transactions')->insert($coin_transactions);
$this->command->info("Saved " . count($coin_transactions) . " coin transactions");
}
if (!empty($coin_purchases)) {
DB::table('coin_purchases')->insert($coin_purchases);
$this->command->info("Saved " . count($coin_purchases) . " coin purchases");
}
$i = 0;
$coin_purchases = [];
$coin_transactions = [];
}
}
$this->command->info("Last block of coin purchases and transactions");
if (!empty($coin_transactions)) {
DB::table('coin_transactions')->insert($coin_transactions);
$this->command->info("Saved " . count($coin_transactions) . " coin transactions");
}
if (!empty($coin_purchases)) {
DB::table('coin_purchases')->insert($coin_purchases);
$this->command->info("Saved " . count($coin_purchases) . " coin purchases");
}
$this->updateAllUsersBalance();
$this->command->info("Game related Transactions Created Successfully.");
}
private function getTimeStampFromDB($strDateFromDB, $minusOneSecond = false)
{
if ($minusOneSecond) {
return date("Y-m-d H:i:s", strtotime($strDateFromDB . " - 1 second"));
}
return date("Y-m-d H:i:s", strtotime($strDateFromDB));
}
private function getRandomPayment($user, &$type, &$ref): void
{
$type = $this->faker->randomElement(['MBWAY', 'PAYPAL', 'IBAN', 'MB', 'VISA']);
switch ($type) {
case 'MBWAY':
$ref = rand(910000000, 999999999);
break;
case 'PAYPAL':
$ref = $user->email;
break;
case 'IBAN':
$ref = 'PT' . rand(5000000000000, 9999999999999) . rand(1000000000, 9999999999);
break;
case 'MB':
$ref = rand(10000, 99999) . '-' . rand(100000000, 999999999);
break;
case 'VISA':
$ref = rand(40000000, 49999999) . rand(10000000, 99999999);
break;
}
}
private $purchaseID = null;
private function addPurchase(&$coin_purchases, &$coin_transactions, &$user, $time, $eurosAmount)
{
$this->purchaseID++;
$coins = $eurosAmount * 10;
$newCoinTransaction = $this->addCoinTransaction($coin_transactions, $user, $coins, 2, $time, null, null);
$this->getRandomPayment($user, $paymentType, $paymentRef);
$coin_purchases[] = [
'id' => $this->purchaseID,
'purchase_datetime' => $time,
'user_id' => $user->id,
'coin_transaction_id' => $newCoinTransaction['id'],
'euros' => $eurosAmount,
'payment_type' => $paymentType,
'payment_reference' => $paymentRef,
'custom' => null,
];
}
private $transactionID = 0;
private function addCoinTransaction(&$coin_transactions, &$user, $coins, $type, $time, $game_id = null, $match_id = null)
{
if ($this->transactionID == null) {
$this->transactionID = DB::table('coin_transactions')->max('id');
}
// Types of coin transactions:
// 1 - Bonus
// 2 - Coin purchase
// 3 - Game fee - requires game_id
// 4 - Match stake - requires match_id
// 5 - Game payout - requires game_id
// 6 - Match payout - requires match_id
if(($type == 3 || $type == 5) && $game_id === null) {
throw new \Exception("Game ID is required for coin transaction type $type");
}
if(($type == 4 || $type == 6) && $match_id === null) {
throw new \Exception("Match ID is required for coin transaction type $type");
}
$this->transactionID++;
$coins = abs($coins);
if (in_array($type, [3, 4])) {
$coins *= -1;
}
$newCoinTransaction = [
'id' => $this->transactionID,
'transaction_datetime' => $time,
'user_id' => $user->id,
'match_id' => $match_id, // nullable
'game_id' => $game_id, // nullable
'coin_transaction_type_id' => $type,
'coins' => $coins,
'custom' => null,
];
$coin_transactions[] = $newCoinTransaction;
$user->coins_balance += $coins;
return $newCoinTransaction;
}
private function calculateGamePayouts($game)
{
$payouts = [0, 0];
if ($game->player1_points == $game->player2_points) {
$payouts = [1, 1];
} elseif ($game->player1_points == 120) {
$payouts = [6, 0];
} elseif ($game->player2_points == 120) {
$payouts = [0, 6];
} elseif ($game->player1_points >= 91) {
$payouts = [4, 0];
} elseif ($game->player2_points >= 91) {
$payouts = [0, 4];
} elseif ($game->player1_points >= 61) {
$payouts = [3, 0];
} elseif ($game->player2_points >= 61) {
$payouts = [0, 3];
} else { // this condition should never be reached
$payouts = [0, 0];
}
return $payouts;
}
private function calculateMatchPayouts($match)
{
$payouts = [0, 0];
if ($match->winner_user_id == $match->player1_user_id) {
$payouts = [$match->stake * 2 - 1, 0];
} elseif ($match->winner_user_id == $match->player2_user_id) {
$payouts = [0, $match->stake * 2 - 1];
}
return $payouts;
}
private function handleGame(&$coin_purchases, &$coin_transactions, $game)
{
$player1 = $this->users->where('id', $game->player1_user_id)->first();
$player2 = $this->users->where('id', $game->player2_user_id)->first();
// not enough coins to play - must purchase before the game
$timeOneSecondBefore = $this->getTimeStampFromDB($game->began_at, true);
if ($player1->coins_balance < 2) {
$this->addPurchase($coin_purchases, $coin_transactions, $player1, $timeOneSecondBefore, random_int(1, 10));
}
// not enough coins to play - must purchase before the game
if ($player2->coins_balance < 2) {
$this->addPurchase($coin_purchases, $coin_transactions, $player2, $timeOneSecondBefore, random_int(1, 10));
}
$this->addCoinTransaction($coin_transactions, $player1, -2, 3, $this->getTimeStampFromDB($game->began_at, false), $game->id);
$this->addCoinTransaction($coin_transactions, $player2, -2, 3, $this->getTimeStampFromDB($game->began_at, false), $game->id);
$payouts = $this->calculateGamePayouts($game);
if ($payouts[0] > 0) {
$this->addCoinTransaction($coin_transactions, $player1, $payouts[0], 5, $this->getTimeStampFromDB($game->ended_at, false), $game->id);
}
if ($payouts[1] > 0) {
$this->addCoinTransaction($coin_transactions, $player2, $payouts[1], 5, $this->getTimeStampFromDB($game->ended_at, false), $game->id);
}
}
private function handleMatch(&$coin_purchases, &$coin_transactions, $match)
{
$player1 = $this->users->where('id', $match->player1_user_id)->first();
$player2 = $this->users->where('id', $match->player2_user_id)->first();
// not enough coins to play - must purchase before the match
$timeOneSecondBefore = $this->getTimeStampFromDB($match->began_at, true);
if ($player1->coins_balance < $match->stake) {
$requiredCoins = $match->stake - $player1->coins_balance;
$euros = ceil(($requiredCoins + 3) / 10);
$this->addPurchase($coin_purchases, $coin_transactions, $player1, $timeOneSecondBefore, $euros);
}
// not enough coins to play - must purchase before the match
if ($player2->coins_balance < $match->stake) {
$requiredCoins = $match->stake - $player2->coins_balance;
$euros = ceil(($requiredCoins + 3) / 10);
$this->addPurchase($coin_purchases, $coin_transactions, $player2, $timeOneSecondBefore, $euros);
}
$this->addCoinTransaction($coin_transactions, $player1, $match->stake * -1, 4, $this->getTimeStampFromDB($match->began_at, false), null, $match->id);
$this->addCoinTransaction($coin_transactions, $player2, $match->stake * -1, 4, $this->getTimeStampFromDB($match->began_at, false), null, $match->id);
$payouts = $this->calculateMatchPayouts($match);
if ($payouts[0] > 0) {
$this->addCoinTransaction($coin_transactions, $player1, $payouts[0], 6, $this->getTimeStampFromDB($match->ended_at, false), null, $match->id);
}
if ($payouts[1] > 0) {
$this->addCoinTransaction($coin_transactions, $player2, $payouts[1], 6, $this->getTimeStampFromDB($match->ended_at, false), null, $match->id);
}
}
private function updateAllUsersBalance()
{
$this->command->info("Update users balances...");
foreach ($this->users as $user) {
DB::table('users')->where('id', $user->id)->update(['coins_balance' => $user->coins_balance]);
}
$this->command->info("All users balances updated.");
}
}