generated from spatie/package-skeleton-laravel
-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a0e6691
commit 4774336
Showing
9 changed files
with
307 additions
and
23 deletions.
There are no files selected for viewing
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
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
<?php | ||
|
||
use Climactic\Credits\Models\Credit; | ||
use Climactic\Credits\Tests\TestModels\User; | ||
|
||
beforeEach(function () { | ||
$this->user = User::create([ | ||
'name' => 'Test User', | ||
'email' => 'test@example.com', | ||
]); | ||
}); | ||
|
||
it('can create a credit transaction', function () { | ||
$credit = Credit::create([ | ||
'creditable_type' => User::class, | ||
'creditable_id' => $this->user->id, | ||
'amount' => 100.00, | ||
'running_balance' => 100.00, | ||
'description' => 'Test credit', | ||
'type' => 'credit', | ||
'metadata' => ['source' => 'test'], | ||
]); | ||
|
||
expect($credit)->toBeInstanceOf(Credit::class) | ||
->and((float)$credit->amount)->toEqual(100.00) | ||
->and($credit->type)->toBe('credit') | ||
->and($credit->metadata)->toBe(['source' => 'test']) | ||
->and($credit->creditable)->toBeInstanceOf(User::class); | ||
}); | ||
|
||
it('casts amount and running_balance as decimals', function () { | ||
$credit = Credit::create([ | ||
'creditable_type' => User::class, | ||
'creditable_id' => $this->user->id, | ||
'amount' => '100.50', | ||
'running_balance' => '100.50', | ||
'type' => 'credit', | ||
]); | ||
|
||
expect((float)$credit->amount)->toEqual(100.50) | ||
->and((float)$credit->running_balance)->toEqual(100.50); | ||
}); | ||
|
||
it('casts metadata as array', function () { | ||
$credit = Credit::create([ | ||
'creditable_type' => User::class, | ||
'creditable_id' => $this->user->id, | ||
'amount' => 100, | ||
'running_balance' => 100, | ||
'type' => 'credit', | ||
'metadata' => ['key' => 'value'], | ||
]); | ||
|
||
expect($credit->metadata)->toBeArray() | ||
->and($credit->metadata)->toBe(['key' => 'value']); | ||
}); | ||
|
||
it('has correct table name from config', function () { | ||
config(['credits.table_name' => 'custom_credits']); | ||
$credit = new Credit(); | ||
|
||
expect($credit->getTable())->toBe('custom_credits'); | ||
}); | ||
|
||
it('belongs to creditable model', function () { | ||
$credit = Credit::create([ | ||
'creditable_type' => User::class, | ||
'creditable_id' => $this->user->id, | ||
'amount' => 100, | ||
'running_balance' => 100, | ||
'type' => 'credit', | ||
]); | ||
|
||
expect($credit->creditable)->toBeInstanceOf(User::class) | ||
->and($credit->creditable->id)->toBe($this->user->id); | ||
}); |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
<?php | ||
|
||
use Climactic\Credits\Tests\TestModels\User; | ||
use Climactic\Credits\Exceptions\InsufficientCreditsException; | ||
|
||
beforeEach(function () { | ||
$this->user = User::create([ | ||
'name' => 'Test User', | ||
'email' => 'test@example.com', | ||
]); | ||
}); | ||
|
||
it('can add credits', function () { | ||
$transaction = $this->user->addCredits(100.00, 'Test credit'); | ||
|
||
expect((float)$transaction->amount)->toEqual(100.00) | ||
->and($transaction->type)->toBe('credit') | ||
->and((float)$transaction->running_balance)->toEqual(100.00) | ||
->and((float)$this->user->getCurrentBalance())->toEqual(100.00); | ||
}); | ||
|
||
it('can deduct credits', function () { | ||
$this->user->addCredits(100.00); | ||
$transaction = $this->user->deductCredits(50.00, 'Test debit'); | ||
|
||
expect((float)$transaction->amount)->toEqual(50.00) | ||
->and($transaction->type)->toBe('debit') | ||
->and((float)$transaction->running_balance)->toEqual(50.00) | ||
->and((float)$this->user->getCurrentBalance())->toEqual(50.00); | ||
}); | ||
|
||
it('prevents negative balance when configured', function () { | ||
config(['credits.allow_negative_balance' => false]); | ||
|
||
$this->user->addCredits(100.00); | ||
|
||
expect(fn() => $this->user->deductCredits(150.00)) | ||
->toThrow(InsufficientCreditsException::class); | ||
}); | ||
|
||
it('allows negative balance when configured', function () { | ||
config(['credits.allow_negative_balance' => true]); | ||
|
||
$this->user->addCredits(100.00); | ||
$transaction = $this->user->deductCredits(150.00); | ||
|
||
expect((float)$transaction->running_balance)->toEqual(-50.00) | ||
->and((float)$this->user->getCurrentBalance())->toEqual(-50.00); | ||
}); | ||
|
||
it('can transfer credits between users', function () { | ||
$recipient = User::create([ | ||
'name' => 'Recipient User', | ||
'email' => 'recipient@example.com', | ||
]); | ||
|
||
$this->user->addCredits(100.00); | ||
$result = $this->user->transferCredits($recipient, 50.00, 'Test transfer'); | ||
|
||
expect($result['sender_balance'])->toBe(50.00) | ||
->and($result['recipient_balance'])->toBe(50.00) | ||
->and($this->user->getCurrentBalance())->toBe(50.00) | ||
->and($recipient->getCurrentBalance())->toBe(50.00); | ||
}); | ||
|
||
it('can get transaction history', function () { | ||
$this->user->addCredits(100.00, 'First credit'); | ||
$this->user->deductCredits(30.00, 'First debit'); | ||
$this->user->addCredits(50.00, 'Second credit'); | ||
|
||
$history = $this->user->getTransactionHistory(10); | ||
|
||
expect($history)->toHaveCount(3) | ||
->and($history->first()->description)->toBe('Second credit'); | ||
}); | ||
|
||
it('can check if has enough credits', function () { | ||
$this->user->addCredits(100.00); | ||
|
||
expect($this->user->hasEnoughCredits(50.00))->toBeTrue() | ||
->and($this->user->hasEnoughCredits(150.00))->toBeFalse(); | ||
}); | ||
|
||
it('can get balance as of date', function () { | ||
$this->user->addCredits(100.00); | ||
|
||
// Move time forward | ||
$this->travel(1)->days(); | ||
|
||
$this->user->addCredits(50.00); | ||
|
||
$pastDate = now()->subDay(); | ||
$balance = $this->user->getBalanceAsOf($pastDate); | ||
|
||
expect($balance)->toBe(100.00); | ||
}); | ||
|
||
it('maintains accurate running balance', function () { | ||
$transactions = collect([ | ||
$this->user->addCredits(100.00), | ||
$this->user->deductCredits(30.00), | ||
$this->user->addCredits(50.00), | ||
$this->user->deductCredits(20.00), | ||
]); | ||
|
||
$expectedBalances = [100.00, 70.00, 120.00, 100.00]; | ||
|
||
$transactions->each(function ($transaction, $index) use ($expectedBalances) { | ||
expect((float)$transaction->running_balance)->toEqual($expectedBalances[$index]); | ||
}); | ||
|
||
expect((float)$this->user->getCurrentBalance())->toEqual(100.00); | ||
}); |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<?php | ||
|
||
use Climactic\Credits\Tests\TestCase; | ||
|
||
uses(TestCase::class)->in(__DIR__); |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
<?php | ||
|
||
namespace Climactic\Credits\Tests; | ||
|
||
use Illuminate\Database\Eloquent\Factories\Factory; | ||
use Orchestra\Testbench\TestCase as Orchestra; | ||
use Climactic\Credits\CreditsServiceProvider; | ||
|
||
class TestCase extends Orchestra | ||
{ | ||
protected function setUp(): void | ||
{ | ||
parent::setUp(); | ||
|
||
Factory::guessFactoryNamesUsing( | ||
fn (string $modelName) => 'Climactic\\Credits\\Database\\Factories\\'.class_basename($modelName).'Factory' | ||
); | ||
} | ||
|
||
protected function getPackageProviders($app) | ||
{ | ||
return [ | ||
CreditsServiceProvider::class, | ||
]; | ||
} | ||
|
||
public function getEnvironmentSetUp($app) | ||
{ | ||
// Use SQLite in memory for testing | ||
config()->set('database.default', 'testing'); | ||
config()->set('database.connections.testing', [ | ||
'driver' => 'sqlite', | ||
'database' => ':memory:', | ||
'prefix' => '', | ||
]); | ||
|
||
// Set up credits config | ||
config()->set('credits.allow_negative_balance', false); | ||
config()->set('credits.decimal_precision', 2); | ||
config()->set('credits.table_name', 'credits'); | ||
config()->set('credits.description.required', false); | ||
config()->set('credits.description.max_length', 255); | ||
} | ||
|
||
protected function defineDatabaseMigrations() | ||
{ | ||
// Include the package migrations | ||
include_once __DIR__.'/../database/migrations/create_credits_table.php.stub'; | ||
(include __DIR__.'/../database/migrations/create_credits_table.php.stub')->up(); | ||
|
||
// Include the test migrations | ||
$this->loadMigrationsFrom(__DIR__ . '/database/migrations'); | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<?php | ||
|
||
namespace Climactic\Credits\Tests\TestModels; | ||
|
||
use Illuminate\Foundation\Auth\User as Authenticatable; | ||
use Climactic\Credits\Traits\HasCredits; | ||
|
||
class User extends Authenticatable | ||
{ | ||
use HasCredits; | ||
|
||
protected $guarded = []; | ||
|
||
protected $table = 'users'; | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<?php | ||
|
||
use Illuminate\Database\Migrations\Migration; | ||
use Illuminate\Database\Schema\Blueprint; | ||
use Illuminate\Support\Facades\Schema; | ||
|
||
return new class extends Migration | ||
{ | ||
public function up() | ||
{ | ||
Schema::create('users', function (Blueprint $table) { | ||
$table->id(); | ||
$table->string('name'); | ||
$table->string('email')->unique(); | ||
$table->timestamps(); | ||
}); | ||
} | ||
|
||
public function down() | ||
{ | ||
Schema::dropIfExists('users'); | ||
} | ||
}; |