Skip to content

Commit

Permalink
feature: add gift domain
Browse files Browse the repository at this point in the history
  • Loading branch information
mascam97 committed Dec 18, 2023
1 parent 5e43b71 commit 3a51693
Show file tree
Hide file tree
Showing 12 changed files with 389 additions and 2 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ sail artisan scribe:generate
- [Queueable actions in Laravel](https://github.com/spatie/laravel-queueable-action)
- [Laravel Model State](https://spatie.be/docs/laravel-model-states/v2/01-introduction) - Advanced state support for Laravel models
- [PEST PHP](https://pestphp.com/) - An elegant PHP Testing Framework
- [MoneyPHP](https://moneyphp.org/) - PHP implementation of Fowler's Money pattern.
- [Scribe](https://scribe.knuckles.wtf/laravel/) - Generate API documentation for humans from your Laravel codebase.

### Authors
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"laravel/vapor-core": "^2.33",
"league/flysystem-aws-s3-v3": "3.0",
"maatwebsite/excel": "^3.1",
"moneyphp/money": "^4.3",
"rebing/graphql-laravel": "^9.1",
"spatie/laravel-activitylog": "^4.7",
"spatie/laravel-data": "^2.1",
Expand Down
90 changes: 89 additions & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions database/factories/DBGiftFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace Database\Factories;

use Domain\Gifts\Models\Gift;
use Illuminate\Database\Eloquent\Factories\Factory;

class DBGiftFactory extends Factory
{
protected $model = Gift::class;

public function definition(): array
{
return [
'note' => $this->faker->text,
'amount' => $this->faker->numberBetween(1, 1000),
'currency' => 'USD',
];
}
}
32 changes: 32 additions & 0 deletions database/migrations/2023_12_18_013819_create_gifts_table.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration {
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('gifts', function (Blueprint $table) {
$table->id();
$table->string('note', 255)->nullable();
$table->bigInteger('amount');
$table->char('currency', 3);
$table->foreignId('user_id')->constrained('users');
$table->foreignId('sender_user_id')->constrained('users');
// TODO: Evaluate if add or not pocket_id field, it can be gotten from the user now
$table->timestamps();
});
}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('gifts');
}
};
44 changes: 44 additions & 0 deletions src/Domain/Gifts/Actions/StoreGiftAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

namespace Domain\Gifts\Actions;

use Domain\Gifts\Data\StoreGiftData;
use Domain\Gifts\Models\Gift;
use Domain\Pockets\Models\Pocket;
use Domain\Users\Models\User;
use Money\Currency;
use Money\Money;

class StoreGiftAction
{
public function __invoke(StoreGiftData $data, User $senderUser, User $user): Gift
{
$userPocket = Pocket::query()->whereId($user->pocket_id)
->select(['id', 'balance', 'currency'])
->first();

// TODO: Throw an error when there is no user pocket

// TODO: Support conversion between currencies
if ($userPocket->currency !== $data->currency) {

Check failure on line 23 in src/Domain/Gifts/Actions/StoreGiftAction.php

View workflow job for this annotation

GitHub Actions / phpstan

Cannot access property $currency on Illuminate\Database\Eloquent\Model|null.
// TODO: Create a custom exception to be handed in the controller
throw new \DomainException('User pocket currency does not match gift currency');
}

$userMoney = new Money($userPocket->balance, new Currency($userPocket->currency)); /* @phpstan-ignore-line */
$giftMoney = new Money($data->amount, new Currency($data->currency));

Check failure on line 29 in src/Domain/Gifts/Actions/StoreGiftAction.php

View workflow job for this annotation

GitHub Actions / phpstan

Parameter #1 $code of class Money\Currency constructor expects non-empty-string, string given.

$userPocket->balance = (int) $userMoney->add($giftMoney)->getAmount();

Check failure on line 31 in src/Domain/Gifts/Actions/StoreGiftAction.php

View workflow job for this annotation

GitHub Actions / phpstan

Cannot access property $balance on Illuminate\Database\Eloquent\Model|null.
$userPocket->save();

Check failure on line 32 in src/Domain/Gifts/Actions/StoreGiftAction.php

View workflow job for this annotation

GitHub Actions / phpstan

Cannot call method save() on Illuminate\Database\Eloquent\Model|null.

$gift = new Gift();
$gift->note = $data->note;
$gift->amount = $data->amount;
$gift->currency = $data->currency;
$gift->senderUser()->associate($senderUser);
$gift->user()->associate($user);
$gift->save();

return $gift;
}
}
26 changes: 26 additions & 0 deletions src/Domain/Gifts/Data/StoreGiftData.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace Domain\Gifts\Data;

use Spatie\LaravelData\Data;

class StoreGiftData extends Data
{
public function __construct(
public ?string $note,
public int $amount,
public string $currency,
) {
}

public static function rules(): array
{
return [
'note' => ['required', 'string', 'min:3', 'max:255'],
// TODO: Add a logic about payment method, where the money is supposed to come from
'amount' => ['required', 'integer', 'min:100'],
// TODO: Add validated currency rule
'currency' => ['required', 'string'],
];
}
}
57 changes: 57 additions & 0 deletions src/Domain/Gifts/Models/Gift.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

namespace Domain\Gifts\Models;

use Database\Factories\DBGiftFactory;
use Domain\Quotes\QueryBuilders\QuoteQueryBuilder;
use Domain\Users\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Carbon;

/**
* @property-read int $id
*
* @property ?string $note
* @property int $amount
* @property string $currency
* @property int $user_id
* @property int $sender_user_id
* @property Carbon $created_at
* @property Carbon $updated_at
*
* @property User $user
* @property User $senderUser
*
* @method static DBGiftFactory factory(...$parameters)
* @method static QuoteQueryBuilder query()
*/
class Gift extends Model
{
use HasFactory;

public function newEloquentBuilder($query): QuoteQueryBuilder
{
return new QuoteQueryBuilder($query);
}

public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}

public function senderUser(): BelongsTo
{
return $this->belongsTo(User::class, 'sender_user_id');
}

/**
* Create a new factory instance for the model.
*/
protected static function newFactory(): Factory
{
return DBGiftFactory::new();
}
}
30 changes: 30 additions & 0 deletions src/Domain/Gifts/QueryBuilders/GiftQueryBuilder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace Domain\Gifts\QueryBuilders;

use Domain\Gifts\Models\Gift;
use Domain\Users\Models\User;
use Illuminate\Database\Eloquent\Builder;

/**
* @method select($columns = ['*'])
* @method count()
* @method Gift firstOrFail($columns = ['*'])
*/
class GiftQueryBuilder extends Builder
{
public function whereId(int $id): self
{
return $this->where('id', $id);
}

public function whereUser(User $user): self
{
return $this->where('user_id', $user->getKey());
}

public function whereSenderUser(User $user): self
{
return $this->where('sender_user_id', $user->getKey());
}
}
2 changes: 1 addition & 1 deletion src/Domain/Users/Models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
* @property ?int $roles_count
*
* @property-read HasMany $quotes
* @property-read HasOne $pocket
* @property-read Pocket $pocket
*
* @method static DBUserFactory factory(...$parameters)
* @method static UserQueryBuilder query()
Expand Down
Loading

0 comments on commit 3a51693

Please sign in to comment.