Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented the functionality of accepting payments from two new gateways #1

Open
wants to merge 14 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,6 @@ npm-debug.log
yarn-error.log
/.idea
/.vscode
_ide_helper.php
_ide_helper_models.php
.phpstorm.meta.php
67 changes: 7 additions & 60 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,66 +1,13 @@
<p align="center"><a href="https://laravel.com" target="_blank"><img src="https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg" width="400" alt="Laravel Logo"></a></p>
# Test task

<p align="center">
<a href="https://travis-ci.org/laravel/framework"><img src="https://travis-ci.org/laravel/framework.svg" alt="Build Status"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/dt/laravel/framework" alt="Total Downloads"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/v/laravel/framework" alt="Latest Stable Version"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/l/laravel/framework" alt="License"></a>
</p>
## Description

## About Laravel
Laravel framework test [task](https://github.com/DvaPacana/test-task-backend)

Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:
## Specification

- [Simple, fast routing engine](https://laravel.com/docs/routing).
- [Powerful dependency injection container](https://laravel.com/docs/container).
- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.
- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).
- Database agnostic [schema migrations](https://laravel.com/docs/migrations).
- [Robust background job processing](https://laravel.com/docs/queues).
- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).
You can read the specification [here](/specification.en.md) ([RU](/specification.ru.md))

Laravel is accessible, powerful, and provides tools required for large, robust applications.
## Requirements and installation

## Learning Laravel

Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework.

You may also try the [Laravel Bootcamp](https://bootcamp.laravel.com), where you will be guided through building a modern Laravel application from scratch.

If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains over 2000 video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.

## Laravel Sponsors

We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the Laravel [Patreon page](https://patreon.com/taylorotwell).

### Premium Partners

- **[Vehikl](https://vehikl.com/)**
- **[Tighten Co.](https://tighten.co)**
- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**
- **[64 Robots](https://64robots.com)**
- **[Cubet Techno Labs](https://cubettech.com)**
- **[Cyber-Duck](https://cyber-duck.co.uk)**
- **[Many](https://www.many.co.uk)**
- **[Webdock, Fast VPS Hosting](https://www.webdock.io/en)**
- **[DevSquad](https://devsquad.com)**
- **[Curotec](https://www.curotec.com/services/technologies/laravel/)**
- **[OP.GG](https://op.gg)**
- **[WebReinvent](https://webreinvent.com/?utm_source=laravel&utm_medium=github&utm_campaign=patreon-sponsors)**
- **[Lendio](https://lendio.com)**

## Contributing

Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).

## Code of Conduct

In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).

## Security Vulnerabilities

If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [[email protected]](mailto:[email protected]). All security vulnerabilities will be promptly addressed.

## License

The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).
Laravel [Sail](https://laravel.com/docs/9.x/sail) (Another [ways](https://laravel.com/docs/9.x/installation))
9 changes: 9 additions & 0 deletions app/Enums/GatewayCodeEnum.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace App\Enums;

enum GatewayCodeEnum: string
{
case One = 'one';
case Two = 'two';
}
9 changes: 5 additions & 4 deletions app/Exceptions/Handler.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
namespace App\Exceptions;

use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Throwable;

class Handler extends ExceptionHandler
{
/**
* A list of exception types with their corresponding custom log levels.
*
* @var array<class-string<\Throwable>, \Psr\Log\LogLevel::*>
* @var array<class-string<Throwable>, \Psr\Log\LogLevel::*>
*/
protected $levels = [
//
Expand All @@ -19,7 +20,7 @@ class Handler extends ExceptionHandler
/**
* A list of the exception types that are not reported.
*
* @var array<int, class-string<\Throwable>>
* @var array<int, class-string<Throwable>>
*/
protected $dontReport = [
//
Expand All @@ -43,8 +44,8 @@ class Handler extends ExceptionHandler
*/
public function register()
{
$this->reportable(function (Throwable $e) {
//
$this->reportable(function (UserApiException $e) {
throw new BadRequestHttpException($e->getMessage());
});
}
}
9 changes: 9 additions & 0 deletions app/Exceptions/LimitExceededException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace App\Exceptions;

use RuntimeException;

class LimitExceededException extends RuntimeException implements UserApiException
{
}
9 changes: 9 additions & 0 deletions app/Exceptions/UserApiException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace App\Exceptions;

use Throwable;

interface UserApiException extends Throwable
{
}
46 changes: 46 additions & 0 deletions app/Http/Controllers/PaymentController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

namespace App\Http\Controllers;

use App\Enums\GatewayCodeEnum;
use App\Http\Dto\PaymentNotificationDto;
use App\Http\Requests\OnePaymentRequest;
use App\Http\Requests\TwoPaymentRequest;
use App\Services\PaymentService;

class PaymentController extends Controller
{
public function __construct(private readonly PaymentService $paymentService)
{
}

public function one(OnePaymentRequest $request)
{
$params = $request->validated();
$this->paymentService->store(
new PaymentNotificationDto(
$params['merchant_id'],
$params['payment_id'],
$params['status'],
$params['amount'],
$params['amount_paid'],
),
GatewayCodeEnum::One
);
}

public function two(TwoPaymentRequest $request)
{
$params = $request->validated();
$this->paymentService->store(
new PaymentNotificationDto(
$params['project'],
$params['invoice'],
$params['status'],
$params['amount'],
$params['amount_paid'],
),
GatewayCodeEnum::Two
);
}
}
15 changes: 15 additions & 0 deletions app/Http/Dto/PaymentNotificationDto.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace App\Http\Dto;

class PaymentNotificationDto
{
public function __construct(
public readonly string $merchantId,
public readonly string $paymentId,
public readonly string $status,
public readonly int $amount,
public readonly int $amountPaid
) {
}
}
22 changes: 22 additions & 0 deletions app/Http/Kernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class Kernel extends HttpKernel
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\JsonMiddleware::class,
],
];

Expand All @@ -64,4 +65,25 @@ class Kernel extends HttpKernel
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
];

/**
* The priority-sorted list of middleware.
*
* Forces non-global middleware to always be in the given order.
*
* @var string[]
*/
protected $middlewarePriority = [
\App\Http\Middleware\JsonMiddleware::class,
\Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class,
\Illuminate\Cookie\Middleware\EncryptCookies::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests::class,
\Illuminate\Routing\Middleware\ThrottleRequests::class,
\Illuminate\Routing\Middleware\ThrottleRequestsWithRedis::class,
\Illuminate\Contracts\Session\Middleware\AuthenticatesSessions::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\Illuminate\Auth\Middleware\Authorize::class,
];
}
25 changes: 25 additions & 0 deletions app/Http/Middleware/JsonMiddleware.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;

class JsonMiddleware
{
/**
* Handle an incoming request.
*
* @param Request $request
* @param Closure(Request): (Response|RedirectResponse) $next
* @return Response|RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
$request->headers->set('Accept', 'application/json');

return $next($request);
}
}
58 changes: 58 additions & 0 deletions app/Http/Requests/OnePaymentRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

namespace App\Http\Requests;

use App\Services\OneRequestSignCheckerService;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\App;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;

class OnePaymentRequest extends FormRequest
{
/**
* Get the validation rules that apply to the request.
*
* @return array<string, mixed>
*/
public function rules(): array
{
return [
'merchant_id' => 'required|int',
'payment_id' => 'required|int',
'status' => 'required|string',
'amount' => 'required|int',
'amount_paid' => 'required|int',
'timestamp' => 'required|int',
'sign' => 'required|string',
];
}

/**
* Prepare the data for validation.
*
* @return void
*/
protected function prepareForValidation(): void
{
if (! $this->isJson()) {
throw new BadRequestHttpException('Wrong content type');
}
}

/**
* Handle a passed validation attempt.
*
* @return void
*
* @throws AuthorizationException
*/
protected function passedValidation(): void
{
/** @var OneRequestSignCheckerService $requestSignService */
$requestSignService = App::make(OneRequestSignCheckerService::class);
if (! $requestSignService->check($this)) {
$this->failedAuthorization();
}
}
}
53 changes: 53 additions & 0 deletions app/Http/Requests/TwoPaymentRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

namespace App\Http\Requests;

use App\Services\TwoRequestSignCheckerService;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\App;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;

class TwoPaymentRequest extends FormRequest
{
/**
* Get the validation rules that apply to the request.
*
* @return array<string, mixed>
*/
public function rules(): array
{
return [
'project' => 'required|int',
'invoice' => 'required|int',
'status' => 'required|string',
'amount' => 'required|int',
'amount_paid' => 'required|int',
'rand' => 'required|string',
];
}

/**
* Prepare the data for validation.
*/
protected function prepareForValidation(): void
{
if ($this->getContentType() !== 'form' || ! $this->hasHeader('Authorization')) {
throw new BadRequestHttpException('Invalid content type and/or header set');
}
}

/**
* Handle a passed validation attempt.
*
* @throws AuthorizationException
*/
protected function passedValidation(): void
{
/** @var TwoRequestSignCheckerService $requestSignService */
$requestSignService = App::make(TwoRequestSignCheckerService::class);
if (! $requestSignService->check($this)) {
$this->failedAuthorization();
}
}
}
Loading