Skip to content

Commit

Permalink
Merge pull request #2 from andeen171/transactions
Browse files Browse the repository at this point in the history
transactions
  • Loading branch information
andeen171 authored Sep 29, 2024
2 parents a7b043b + c3a0998 commit fb737e5
Show file tree
Hide file tree
Showing 45 changed files with 1,420 additions and 36 deletions.
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,6 @@ REDIS_HOST=host.docker.internal
REDIS_AUTH=(null)
REDIS_PORT=6379
REDIS_DB=0

AUTHORIZATION_SERVICE_URL=https://util.devi.tools/api/v2/
NOTIFICATION_SERVICE_URL=https://util.devi.tools/api/v1/
5 changes: 0 additions & 5 deletions app/Controller/AuthController.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,4 @@ public function signIn(SignInRequest $request, ResponseInterface $response): Psr

return $response->json(['token' => $jwt]);
}

public function user(): PsrResponseInterface
{
return UserResource::make($this->authService->getLoggedUser())->toResponse();
}
}
31 changes: 31 additions & 0 deletions app/Controller/TransactionController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace App\Controller;

use App\Request\TransferRequest;
use App\Resource\TransactionResource;
use App\Service\TransactionService;
use Psr\Http\Message\ResponseInterface as PsrResponseInterface;
use Throwable;

class TransactionController
{
public function __construct(
protected readonly TransactionService $transactionService,
)
{
}

/**
* @throws Throwable
*/
public function transfer(TransferRequest $request): PsrResponseInterface
{
$transaction = $this->transactionService->transfer($request->validated());

return TransactionResource::make($transaction);
}

}
43 changes: 43 additions & 0 deletions app/Controller/UserController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

declare(strict_types=1);

namespace App\Controller;

use App\Repository\UserRepository;
use App\Request\ListShopkeepersRequest;
use App\Request\ListUsersRequest;
use App\Request\ShowUserRequest;
use App\Resource\UserResource;
use App\Service\AuthService;
use Psr\Http\Message\ResponseInterface as PsrResponseInterface;

class UserController
{
public function __construct(
protected readonly UserRepository $repository,
)
{
}

public function loggedUser(AuthService $authService): PsrResponseInterface
{
return UserResource::make($authService->getLoggedUser())->toResponse();
}

public function listUsers(ListUsersRequest $request): PsrResponseInterface
{
return UserResource::collection($this->repository->listUsers($request->validated()))->toResponse();
}

public function listShopkeepers(ListShopkeepersRequest $request): PsrResponseInterface
{
return UserResource::collection($this->repository->listShopKeepers($request->validated()))->toResponse();
}

public function showUser(ShowUserRequest $request): PsrResponseInterface
{
return UserResource::make($request->getItem())->toResponse();
}

}
3 changes: 3 additions & 0 deletions app/Enum/ExceptionMessageCodeEnum.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@ enum ExceptionMessageCodeEnum: string
case USER_NOT_FOUND = 'user_not_found';
case WRONG_CREDENTIALS = 'wrong_credentials';
case UNAUTHORIZED = 'unauthorized';
case INSUFFICIENT_FUNDS = 'insufficient_funds';
case TRANSACTION_FAILED = 'transaction_failed';
case SHOPKEEPER_CANNOT_TRANSFER = 'shopkeeper_cannot_transfer';
}
16 changes: 16 additions & 0 deletions app/Exception/InsufficientFundsException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace App\Exception;

use App\Enum\ExceptionMessageCodeEnum;
use Swoole\Http\Status;

class InsufficientFundsException extends AbstractException
{
public function __construct()
{
$code = Status::FORBIDDEN;
$message = ExceptionMessageCodeEnum::INSUFFICIENT_FUNDS;
parent::__construct($message, $code);
}
}
16 changes: 16 additions & 0 deletions app/Exception/ShopkeeperCannotTransferException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace App\Exception;

use App\Enum\ExceptionMessageCodeEnum;
use Swoole\Http\Status;

class ShopkeeperCannotTransferException extends AbstractException
{
public function __construct()
{
$code = Status::FORBIDDEN;
$message = ExceptionMessageCodeEnum::SHOPKEEPER_CANNOT_TRANSFER;
parent::__construct($message, $code);
}
}
17 changes: 17 additions & 0 deletions app/Exception/TransactionFailedException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace App\Exception;

use App\Enum\ExceptionMessageCodeEnum;
use Swoole\Http\Status;
use Throwable;

class TransactionFailedException extends AbstractException
{
public function __construct(Throwable $previous)
{
$code = Status::FAILED_DEPENDENCY;
$message = ExceptionMessageCodeEnum::TRANSACTION_FAILED;
parent::__construct($message, $code, $previous);
}
}
50 changes: 50 additions & 0 deletions app/Model/Transaction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

declare(strict_types=1);

namespace App\Model;

use Carbon\Carbon;
use Hyperf\Database\Model\Relations\BelongsTo;
use Hyperf\DbConnection\Model\Model;

/**
* @property int $id
* @property int $amount
* @property int $payer_user_id
* @property int $payee_user_id
* @property Carbon $created_at
* @property Carbon $updated_at
* @property-read User $payer
* @property-read User $payee
*/
class Transaction extends Model
{
protected ?string $table = 'transactions';

protected array $fillable = [
'amount',
'payer_user_id',
'payee_user_id',
];

protected array $casts = [
'id' => 'integer',
'amount' => 'integer',
'payer_user_id' => 'integer',
'payee_user_id' => 'integer',
'created_at' => 'datetime',
'updated_at' => 'datetime'
];

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


public function payee(): BelongsTo
{
return $this->belongsTo(User::class, 'payee_user_id');
}
}
27 changes: 27 additions & 0 deletions app/Model/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
namespace App\Model;

use Carbon\Carbon;
use Hyperf\Database\Model\Collection;
use Hyperf\Database\Model\Events\Created;
use Hyperf\Database\Model\Relations\HasMany;
use Hyperf\Database\Model\Relations\HasOne;

/**
* @property int $id
Expand All @@ -16,6 +20,9 @@
* @property string $type
* @property Carbon $created_at
* @property Carbon $updated_at
* @property-read Wallet $wallet
* @property-read Collection<Transaction> $sentTransactions
* @property-read Collection<Transaction> $receivedTransactions
*/
class User extends Model
{
Expand All @@ -35,4 +42,24 @@ class User extends Model
'created_at' => 'datetime',
'updated_at' => 'datetime'
];

public function created(Created $event): void
{
$this->wallet()->create();
}

public function wallet(): HasOne
{
return $this->hasOne(Wallet::class, 'user_id', 'id');
}

public function sentTransactions(): HasMany
{
return $this->hasMany(Transaction::class, 'payer_id', 'id');
}

public function receivedTransactions(): HasMany
{
return $this->hasMany(Transaction::class, 'payee_id', 'id');
}
}
40 changes: 40 additions & 0 deletions app/Model/Wallet.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

declare(strict_types=1);

namespace App\Model;

use Carbon\Carbon;
use Hyperf\Database\Model\Relations\BelongsTo;
use Hyperf\DbConnection\Model\Model;

/**
* @property int $id
* @property int $balance
* @property int $user_id
* @property Carbon $created_at
* @property Carbon $updated_at
* @property-read User $user
*/
class Wallet extends Model
{
protected ?string $table = 'wallets';

protected array $fillable = [
'balance',
'user_id'
];

protected array $casts = [
'id' => 'integer',
'created_at' => 'datetime',
'updated_at' => 'datetime',
'balance' => 'integer',
'user_id' => 'integer'
];

public function user(): BelongsTo
{
return $this->belongsTo(User::class, 'user_id');
}
}
42 changes: 42 additions & 0 deletions app/Repository/UserRepository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace App\Repository;

use App\Enum\UserTypeEnum;
use App\Model\User;
use Hyperf\Contract\LengthAwarePaginatorInterface;

class UserRepository
{
/**
* @param array{
* page: ?integer,
* perPage: ?integer,
* } $filters
*/
public function listShopKeepers(array $filters): LengthAwarePaginatorInterface
{
return User::query()
->where('type', UserTypeEnum::SHOPKEEPER->value)
->paginate(
perPage: $filters['perPage'] ?? null,
page: $filters['page'] ?? null
);
}

/**
* @param array{
* page: ?integer,
* perPage: ?integer,
* } $filters
*/
public function listUsers(array $filters): LengthAwarePaginatorInterface
{
return User::query()
->where('type', UserTypeEnum::COMMON->value)
->paginate(
perPage: $filters['perPage'] ?? null,
page: $filters['page'] ?? null
);
}
}
28 changes: 28 additions & 0 deletions app/Request/ListShopkeepersRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace App\Request;

use Hyperf\Validation\Request\FormRequest;

class ListShopkeepersRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}

/**
* Get the validation rules that apply to the request.
*/
public function rules(): array
{
return [

];
}
}
28 changes: 28 additions & 0 deletions app/Request/ListUsersRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace App\Request;

use Hyperf\Validation\Request\FormRequest;

class ListUsersRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}

/**
* Get the validation rules that apply to the request.
*/
public function rules(): array
{
return [

];
}
}
Loading

0 comments on commit fb737e5

Please sign in to comment.