Skip to content

Commit

Permalink
Laravel 11
Browse files Browse the repository at this point in the history
  • Loading branch information
MannikJ committed Jul 1, 2024
1 parent c5631a5 commit 05f268a
Show file tree
Hide file tree
Showing 13 changed files with 117 additions and 67 deletions.
3 changes: 1 addition & 2 deletions .devcontainer/devcontainer.example.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@
"artdiniz.quitcontrol-vscode",
"mikestead.dotenv",
"ryu1kn.partial-diff",
"emallin.phpunit",
"calebporzio.better-phpunit",
"eamodio.gitlens",
"onecentlin.laravel-extension-pack",
"onecentlin.php-productive-pack",
"beyondcode.tinkerwell"
],
"remoteUser": "laradock",
"shutdownAction": "none"
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ vendor
coverage
.phpunit.result.cache
/.phpunit.cache
devcontainer.json
devcontainer.json
/database/database.sqlite
13 changes: 6 additions & 7 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,14 @@
}
],
"require": {
"php": "^8.1",
"illuminate/support": "^10.0"
"php": "^8.2"
},
"require-dev": {
"doctrine/dbal": "^3.6",
"laravel/pint": "*",
"nunomaduro/larastan": "^2.5",
"orchestra/testbench": "^8.0",
"phpunit/phpunit": "^10.0"
"doctrine/dbal": "^4.0",
"laravel/pint": "1.16.1",
"larastan/larastan": "^2.9",
"orchestra/testbench": "^9.1.1",
"phpunit/phpunit": "^11.1"
},
"autoload": {
"psr-4": {
Expand Down
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ public function up()
->after('wallet_id');
});
Schema::table($transactionTable, function (Blueprint $table) {
$table->unsignedInteger('reference_id')->nullable()->after('wallet_id');
$table->unsignedInteger('reference_id')
->nullable()
->after('wallet_id');
});
}

Expand All @@ -35,10 +37,10 @@ public function down()
$transactionModelClass = config('wallet.transaction_model');
$transactionTable = (new $transactionModelClass())->getTable();
Schema::table($transactionTable, function (Blueprint $table) {
$table->dropColumn(['reference_type']);
$table->dropColumn('reference_type');
});
Schema::table($transactionTable, function (Blueprint $table) {
$table->dropColumn(['reference_id']);
$table->dropColumn('reference_id');
});
}
}
2 changes: 1 addition & 1 deletion phpstan.neon
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
includes:
- ./vendor/nunomaduro/larastan/extension.neon
- ./vendor/larastan/larastan/extension.neon

parameters:

Expand Down
10 changes: 10 additions & 0 deletions src/Facades/WalletFacade.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,17 @@
use Illuminate\Support\Facades\Facade;

/**
*
* @method static mixed config(string $relativePath, mixed $default)
* @method static array addingTransactionTypes()
* @method static array subtractingTransactionTypes()
* @method static array unbiasedTransactionTypes()
* @method static array biasedTransactionTypes()
* @method static array transactionTypes()
* @method static bool autoRecalculationActive()
*
* @see \MannikJ\Laravel\Wallet\Models\Wallet
* @mixin \MannikJ\Laravel\Wallet\Models\Wallet
*/
class WalletFacade extends Facade
{
Expand Down
62 changes: 37 additions & 25 deletions src/Models/Wallet.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ class Wallet extends Model implements ValidModelConstructor
public function __construct(array $attributes = [])
{
$type = config('wallet.column_type');
if ($type == 'decimal') {
$this->casts['balance'] = 'float';
} elseif ($type == 'integer') {
$this->casts['balance'] = 'integer';
}

$this->casts['balance'] = $type === 'decimal'
? 'float'
: 'integer';

parent::__construct($attributes);
}

Expand All @@ -62,12 +62,12 @@ public function owner(): MorphTo
* @param int $amount
* @return MannikJ\Laravel\Wallet\Models\Transaction
*/
public function deposit(int|float $amount, array $meta = [], string $type = 'deposit', bool $forceFail = false): Transaction
public function deposit(float $amount, array $meta = [], string $type = 'deposit', bool $forceFail = false): Transaction
{
$accepted = $amount >= 0
&& ! $forceFail ? true : false;
&& !$forceFail ? true : false;

if (! $this->exists) {
if (!$this->exists) {
$this->save();
}

Expand All @@ -79,7 +79,7 @@ public function deposit(int|float $amount, array $meta = [], string $type = 'dep
'deleted_at' => $accepted ? null : now(),
]);

if (! $accepted && ! $forceFail) {
if (!$accepted && !$forceFail) {
throw new UnacceptedTransactionException($transaction, 'Deposit not accepted!');
}

Expand All @@ -91,27 +91,27 @@ public function deposit(int|float $amount, array $meta = [], string $type = 'dep
/**
* Fail to move credits to this account.
*
* @param int $amount
* @param float $amount
* @return MannikJ\Laravel\Wallet\Models\Transaction
*/
public function failDeposit(int|float $amount, array $meta = [], string $type = 'deposit'): Transaction
public function failDeposit(float $amount, array $meta = [], string $type = 'deposit'): Transaction
{
return $this->deposit($amount, $meta, $type, true);
}

/**
* Attempt to move credits from this account.
*
* @param int $amount Only the absolute value will be considered
* @param float $amount Only the absolute value will be considered
* @return MannikJ\Laravel\Wallet\Models\Transaction
*/
public function withdraw(int|float $amount, array $meta = [], string $type = 'withdraw', bool $guarded = true)
public function withdraw(float $amount, array $meta = [], string $type = 'withdraw', bool $guarded = true)
{
$accepted = $guarded
? $this->canWithdraw($amount)
: true;

if (! $this->exists) {
if (!$this->exists) {
$this->save();
}

Expand All @@ -123,7 +123,7 @@ public function withdraw(int|float $amount, array $meta = [], string $type = 'wi
'deleted_at' => $accepted ? null : now(),
]);

if (! $accepted) {
if (!$accepted) {
throw new UnacceptedTransactionException($transaction, 'Withdrawal not accepted due to insufficient funds!');
}

Expand All @@ -135,7 +135,7 @@ public function withdraw(int|float $amount, array $meta = [], string $type = 'wi
/**
* Move credits from this account.
*
* @param int $amount
* @param float $amount
*/
public function forceWithdraw(int|float $amount, array $meta = [], string $type = 'withdraw')
{
Expand All @@ -145,28 +145,37 @@ public function forceWithdraw(int|float $amount, array $meta = [], string $type
/**
* Determine if the user can withdraw the given amount.
*
* @param int $amount
* @param float $amount
* @return bool
*/
public function canWithdraw(int|float $amount = null)
public function canWithdraw(float $amount = null)
{
return $amount ? $this->balance >= abs($amount) : $this->balance > 0;
return $amount
? $this->balance >= abs($amount)
: $this->balance > 0;
}

/**
* Set wallet balance to desired value.
* Will automatically create the necessary transaction.
*
* @param int $balance
* @param float $balance
* @param string $comment
* @return MannikJ\Laravel\Wallet\Models\Transaction
*/
public function setBalance(int|float $amount, string $comment = 'Manual offset transaction')
public function setBalance(float $amount, string $comment = 'Manual offset transaction')
{
$actualBalance = $this->actualBalance();
$difference = $amount - $actualBalance;

if ($difference == 0) {
return;
}
$type = $difference > 0 ? 'deposit' : 'forceWithdraw';

$type = $difference > 0
? 'deposit'
: 'forceWithdraw';

$this->balance = $actualBalance;
$this->save();

Expand All @@ -177,20 +186,23 @@ public function setBalance(int|float $amount, string $comment = 'Manual offset t
* Returns the actual balance for this wallet.
* Might be different from the balance property if the database is manipulated.
*
* @param bool $save
* @return float balance
*/
public function actualBalance(bool $save = false)
public function actualBalance(bool $save = false): float
{
$undefined = $this->transactions()
->whereNotIn('type', WalletFacade::biasedTransactionTypes())
->sum('amount');

$credits = $this->transactions()
->whereIn('type', WalletFacade::addingTransactionTypes())
->sum(DB::raw('abs(amount)'));
->sum(DB::raw('ABS(amount)'));

$debits = $this->transactions()
->whereIn('type', WalletFacade::subtractingTransactionTypes())
->sum(DB::raw('abs(amount)'));
->sum(DB::raw('ABS(amount)'));

$balance = $undefined + $credits - $debits;

if ($save) {
Expand Down
11 changes: 11 additions & 0 deletions src/Services/Wallet.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,17 @@

class Wallet
{
public function config($relativePath, $default)
{
$path = "wallet";

if ($relativePath) {
$path .= ".$relativePath";
}

return config($path, $default);
}

public function addingTransactionTypes(): array
{
return config('wallet.adding_transaction_types', []);
Expand Down
8 changes: 6 additions & 2 deletions tests/unit/HasWalletTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,20 @@

namespace MannikJ\Laravel\Wallet\Tests\Unit;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Collection;
use MannikJ\Laravel\Wallet\Models\Wallet;
use MannikJ\Laravel\Wallet\Tests\Factories\TransactionFactory;
use MannikJ\Laravel\Wallet\Tests\Factories\UserFactory;
use MannikJ\Laravel\Wallet\Tests\Factories\WalletFactory;
use MannikJ\Laravel\Wallet\Tests\TestCase;
use PHPUnit\Framework\Attributes\Test;

class HasWalletTest extends TestCase
{
/** @test */
use RefreshDatabase;

#[Test]
public function wallet()
{
$user = UserFactory::new()->create();
Expand All @@ -20,7 +24,7 @@ public function wallet()
$this->assertTrue($user->wallet->balance === 0.0);
}

/** @test */
#[Test]
public function wallet_transactions()
{
$user1 = UserFactory::new()->create();
Expand Down
6 changes: 5 additions & 1 deletion tests/unit/RecalculateWalletBalanceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@

namespace MannikJ\Laravel\Wallet\Tests\Unit;

use Illuminate\Foundation\Testing\RefreshDatabase;
use MannikJ\Laravel\Wallet\Jobs\RecalculateWalletBalance;
use MannikJ\Laravel\Wallet\Models\Transaction;
use MannikJ\Laravel\Wallet\Tests\Factories\WalletFactory;
use MannikJ\Laravel\Wallet\Tests\TestCase;
use PHPUnit\Framework\Attributes\Test;

class RecalculateWalletBalanceTest extends TestCase
{
/** @test */
use RefreshDatabase;

#[Test]
public function dispatch()
{
config(['wallet.auto_recalculate_balance' => true]);
Expand Down
Loading

0 comments on commit 05f268a

Please sign in to comment.