Subiendo proyecto completo sin restricciones de git ignore

This commit is contained in:
Jose Sanchez
2023-08-17 11:44:02 -04:00
parent a0d4f5ba3b
commit 20f1c60600
19921 changed files with 2509159 additions and 45 deletions

View File

@@ -0,0 +1,33 @@
/node_modules
/public/hot
/public/storage
/storage/*.key
/vendor
.env
.env.backup
.phpunit.result.cache
Homestead.json
Homestead.yaml
npm-debug.log
yarn-error.log
# Eliminar archivos de macOS
.DS_Store
# Eliminar archivos generados por Mix
/public/js/*
/public/css/*
# No subir mix-manifest
public/mix-manifest.json
# No subir los logs de clockwork
/storage/clockwork/*
# Archivos de PhpStorm
.idea
_ide_helper.php
_ide_helper_models.php
.phpstorm.meta.php
.npm-install-changed.json

View File

@@ -0,0 +1,41 @@
{
"name": "sebacarrasco93/laravel-payku",
"type": "package",
"description": "Payku Package for Laravel",
"license": "MIT",
"authors": [
{
"name": "Seba Carrasco Poblete",
"email": "sebacarrasco93@gmail.com"
}
],
"autoload": {
"psr-4": {
"SebaCarrasco93\\LaravelPayku\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"SebaCarrasco93\\LaravelPayku\\Tests\\": "tests"
}
},
"require": {
"guzzlehttp/guzzle": "^7.0.1",
"php": "^7.3|^8.0"
},
"require-dev": {
"orchestra/testbench": "^6.18",
"pestphp/pest": "^1.3"
},
"extra": {
"laravel": {
"providers": [
"SebaCarrasco93\\LaravelPayku\\LaravelPaykuServiceProvider",
"SebaCarrasco93\\LaravelPayku\\RouteServiceProvider"
],
"aliases": {
"LaravelPayku": "SebaCarrasco93\\LaravelPayku\\Facades\\LaravelPayku"
}
}
}
}

7972
vendor/sebacarrasco93/laravel-payku/composer.lock generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,47 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| API data
|--------------------------------------------------------------------------
|
| Copy the keys and place their values in your .env file
| You can get it from https://app.payku.cl/usuarios/tokenintegracion
|
*/
'base_url' => env('PAYKU_BASE_URL'),
'public_token' => env('PAYKU_PUBLIC_TOKEN'),
'private_token' => env('PAYKU_PRIVATE_TOKEN'),
/*
|--------------------------------------------------------------------------
| Routes
|--------------------------------------------------------------------------
|
| You can change the "prefix" from the URL route, by default is: "payku"
| So, the full "url" will be: https://yourdomain.com/payku
|
|
*/
'route_prefix' => 'payku',
/*
|--------------------------------------------------------------------------
| Finished Route name
|--------------------------------------------------------------------------
|
| You can set a custom name for showing the final result of transaction
|
|
*/
'route_finish_name' => env('PAYKU_ROUTE_FINISH_NAME', 'payku.result'),
];

View File

@@ -0,0 +1,39 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreatePaykuTransactionsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('payku_transactions', function (Blueprint $table) {
$table->string('id')->index()->unique(); // transaction_id: 1, 2, 3
$table->string('status')->nullable(); // ['success', '...']
$table->string('order')->nullable()->unique(); // before: order: trx8956fbcc9e5f4ba62
$table->string('email')->nullable();
$table->string('subject')->nullable();
$table->text('url')->nullable();
$table->unsignedInteger('amount')->nullable();
$table->datetime('notified_at')->nullable();
$table->timestamp('created_at')->nullable();
$table->timestamp('updated_at')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('payku_transactions');
}
}

View File

@@ -0,0 +1,44 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreatePaykuPaymentsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('payku_payments', function (Blueprint $table) {
$table->string('transaction_id')->unique();
$table->date('start');
$table->date('end');
$table->string('media');
$table->string('verification_key');
$table->string('authorization_code');
$table->unsignedInteger('last_4_digits')->nullable();
$table->string('installments')->nullable();
$table->string('card_type')->nullable();
$table->string('additional_parameters')->nullable();
$table->string('currency');
$table->timestamp('created_at')->nullable();
$table->timestamp('updated_at')->nullable();
$table->foreign('transaction_id')->references('id')->on('payku_transactions');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('payku_payments');
}
}

View File

@@ -0,0 +1,36 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddNewColumnsToTables extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('payku_transactions', function (Blueprint $table) {
$table->string('full_name')->nullable();
});
Schema::table('payku_payments', function (Blueprint $table) {
$table->string('payment_key')->nullable();
$table->string('transaction_key')->nullable();
$table->datetime('deposit_date')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('payku_payments');
}
}

View File

@@ -0,0 +1,5 @@
# Facade
LaravelPayku::knowFilledKeys();
LaravelPayku::hasValidConfig();
LaravelPayku::createOrder();

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="vendor/autoload.php"
colors="true"
>
<testsuites>
<testsuite name="Test Suite">
<directory suffix="Test.php">./tests</directory>
</testsuite>
</testsuites>
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">./app</directory>
<directory suffix=".php">./src</directory>
</include>
</coverage>
</phpunit>

View File

@@ -0,0 +1,13 @@
#### Changing API URL
If you want to use a specific URL by ignoring the "normal" functionality of Package, the only thing you need to to add is a `PAYKU_BASE_URL` key to your project's `.env` file
```bash
PAYKU_BASE_URL=https://des.payku.cl/api
```
or...
```bash
PAYKU_BASE_URL=https://app.payku.cl/api
```

View File

@@ -0,0 +1,66 @@
# Laravel Payku
📦 A simple implementation, and ready to use package for Payku.
### Requirements
- Laravel 8 or above
### Installation
```bash
composer require sebacarrasco93/laravel-payku
```
#### Adding .env keys
You need to create a public and private token. You can create and get it from:
- [Payku Development environment](https://des.payku.cl/usuarios/tokenintegracion)
- [Payku Production environment](https://app.payku.cl/usuarios/tokenintegracion)
```bash
PAYKU_PUBLIC_TOKEN={your_public_token}
PAYKU_PRIVATE_TOKEN={your_private_token}
```
#### Important:
Laravel Payku automatically will set the environment URL based in your `APP_ENV` key, in your `.env` project's file
For example, if you set your `APP_ENV` to `local`, it will use `https://des.payku.cl/api`
```bash
APP_ENV=local # will set https://des.payku.cl/api
```
Otherwise, if your `APP_ENV` is on `production`, it will use `https://app.payku.cl/api`
```bash
APP_ENV=production # will set https://app.payku.cl/api
```
If you want to force a specific API URL in another environment, you can [learn how to do it](readme-changing-api-url.md)
### Usage
Example of a method
```php
//
```
Easy Peasy!
### Extra
If you want more control, you can publish the migrations and configuration
```bash
php artisan vendor:publish --provider="SebaCarrasco93\LaravelPayku\LaravelPaykuServiceProvider"
```
### Testing
```bash
./vendor/bin/pest
```

View File

@@ -0,0 +1,8 @@
<?php
return [
'title' => 'Missing route',
'it_works' => 'It works!',
'finished_1' => 'Your order was finished! but if you want to show a nice view, you need to create a route with name',
'finished_2' => 'to showing final result to your user',
];

View File

@@ -0,0 +1,8 @@
<?php
return [
'title' => 'Falta una ruta',
'it_works' => 'Funciona!',
'finished_1' => 'Tu orden fue creada! pero si quieres agregar una hermosa vista, necesitas crear una ruta con el nombre',
'finished_2' => 'para mostrar el resultado final a tu usuario',
];

View File

@@ -0,0 +1,105 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Laravel Payku | {{ trans('laravel-payku::missing.title') }}</title>
</head>
<body>
<header>
<img src="https://payku.cl/wp-content/uploads/2019/05/payku_2x.png" alt="">
<h1>{{ trans('laravel-payku::missing.it_works') }}</h1>
</header>
<div class="detail">
<div class="group">
<div class="title">ID:</div>
<div class="value">{{ $result->id }}</div>
</div>
<div class="group">
<div class="title">Status:</div>
<div class="value">{{ $result->status }}</div>
</div>
<div class="group">
<div class="title">Order:</div>
<div class="value">{{ $result->order }}</div>
</div>
<div class="group">
<div class="title">Email:</div>
<div class="value">{{ $result->email }}</div>
</div>
<div class="group">
<div class="title">Subject:</div>
<div class="value">{{ $result->subject }}</div>
</div>
<div class="group">
<div class="title">Amount:</div>
<div class="value">{{ $result->amount }}</div>
</div>
</div>
<p>{{ trans('laravel-payku::missing.finished_1') }} "<strong>{{ $routeName }}</strong>", {{ trans('laravel-payku::missing.finished_2') }}</p>
<pre>{{ $result }}</pre>
</body>
</html>
<style>
@import('https://fonts.googleapis.com/css2?family=Karla:wght@400;600&display=swap');
:root {
--color-one: #000036;
--color-two: #00E48C;
--color-three: #fff;
}
* {
margin: 0;
padding: 0;
}
html {
font-family: 'Karla', sans-serif;
background: #1b2032;
color: var(--color-three);
text-align: center;
}
header {
background: #4d39e9;
padding: 30px 40px;
display: flex;
justify-content: space-between;
}
h1 {
}
.detail {
background: var(--color-three);
color: var(--color-one);
display: grid;
grid-template-columns: 1fr 1fr 1fr;
padding: 50px 5px;
}
.group {
margin: 5px;
}
.title {
font-weight: 600;
}
pre {
margin: 20px;
white-space: pre-wrap;
word-wrap: break-word;
}
p {
color: #f8b526;
padding: 10px;
}
</style>

View File

@@ -0,0 +1,7 @@
<?php
use SebaCarrasco93\LaravelPayku\Http\Controllers\PaykuController;
Route::post('/', [PaykuController::class, 'create'])->name('create');
Route::get('/return/{order}', [PaykuController::class, 'return'])->name('return');
Route::get('/notify/{order}', [PaykuController::class, 'notify'])->name('notify');

View File

@@ -0,0 +1,13 @@
<?php
namespace SebaCarrasco93\LaravelPayku\Facades;
use Illuminate\Support\Facades\Facade;
class LaravelPayku extends Facade
{
protected static function getFacadeAccessor()
{
return 'laravel-payku';
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace SebaCarrasco93\LaravelPayku\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use SebaCarrasco93\LaravelPayku\Facades\LaravelPayku;
use SebaCarrasco93\LaravelPayku\Models\PaykuTransaction;
class PaykuController
{
public function create(Request $request)
{
$data = $request->validate([
'email' => 'required|email',
'order' => 'required|unique:payku_transactions,id',
'subject' => 'required',
'amount' => 'required|int',
]);
return LaravelPayku::create($data['order'], $data['subject'], $data['amount'], $data['email']);
}
public function return($order)
{
$detail = LaravelPayku::return($order);
return $detail;
}
public function notify($order)
{
$result = LaravelPayku::notify($order);
$routeName = config('laravel-payku.route_finish_name');
$routeExists = Route::has($routeName);
if ($routeExists) {
return redirect()->route($routeName, $result);
}
return view('payku::notify.missing-route', compact('result', 'routeName'));
}
}

View File

@@ -0,0 +1,175 @@
<?php
namespace SebaCarrasco93\LaravelPayku;
use SebaCarrasco93\LaravelPayku\Models\PaykuTransaction;
use SebaCarrasco93\LaravelPayku\Traits\DatabaseSimulation;
use SebaCarrasco93\LaravelPayku\Traits\PrepareOrders;
use GuzzleHttp\Client as GuzzleClient;
use Illuminate\Support\Collection;
class LaravelPayku
{
use DatabaseSimulation, PrepareOrders;
// From Response API
public $hasValidResponse = false;
public $status, $id, $created_at, $order, $email, $subject, $amount;
// URLs
const URL_API_DEV = 'https://des.payku.cl/api';
const URL_API_PROD = 'https://app.payku.cl/api';
// For API Interaction...
public $client;
public $minimumApiKeys = ['public_token', 'private_token'];
// For handle with API
public $allowedTransactionsStatuses = ['register', 'pending', 'success', 'failed'];
// public $allowedTransactionsKeys = ['status', 'id', 'created_at', 'order', 'email', 'subject', 'amount'];
public $allowedPaymentKeys = [
'start', 'end', 'media', 'transaction_id', 'verification_key', 'authorization_code',
'last_4_digits', 'installments', 'card_type', 'additional_parameters', 'currency',
];
public function __construct()
{
$this->client = new GuzzleClient([
'headers' => [
'Authorization' => 'Bearer ' . config('laravel-payku.public_token'),
'User-Agent' => 'sebacarrasco93/laravel-payku'
],
'base_uri' => $this->apiRoute() . '/'
]);
$this->hasValidConfig();
}
public function apiRoute()
{
if (config('laravel-payku.base_url')) {
return config('laravel-payku.base_url');
}
if (config('app.env') == 'production') {
return self::URL_API_PROD;
}
return self::URL_API_DEV;
}
public function findApiKeys()
{
$found = [];
foreach ($this->minimumApiKeys as $key) {
$found[$key] = config('laravel-payku')[$key];
}
return array_filter($found);
}
public function hasValidConfig()
{
$count = count($this->minimumApiKeys);
if (count($this->findApiKeys()) == $count) {
return true;
}
throw new \Exception('Please set all PAYKU keys in your .env file.');
}
public function postApi(string $transaction_id, string $subject, int $amountCLP, string $email)
{
$body = $this->client->request('POST', 'transaction', [
'json' => $this->prepareOrder($transaction_id, $subject, $amountCLP, $email),
])->getBody();
return json_decode($body, true);
}
public function getApi(PaykuTransaction $transaction)
{
$body = $this->client->request('GET', 'transaction/' . $transaction->id)->getBody();
return json_decode($body, true);
}
public function handleAPIResponse($response)
{
if (! in_array($response['status'], $this->allowedTransactionsStatuses)) {
throw new \Exception("Invalid response status: " . $response['status']);
}
$this->hasValidResponse = true;
// $this->status = $response['status'];
foreach ($response as $key => $value) {
$this->$key = $value;
}
}
public function saveAPIResponse($response, $transaction_id = null)
{
$response = collect($response);
$this->handleAPIResponse($response);
// dd($response);
if ($transaction_id) { // Creating...
$response['order'] = $transaction_id;
}
$firstResponse = $response->except('payment', 'gateway_response')->toArray();
if ($firstResponse['status'] != 'failed') {
$transaction = PaykuTransaction::updateOrCreate(['id' => $response['id']], $firstResponse);
if (isset($response['payment'])) {
$payment = collect($response['payment']);
if ($payment->count()) {
$transaction->payment()->create($payment->toArray());
}
}
} else {
throw new \Exception("Can't create your transaction with ID ${transaction_id}");
}
}
public function create(string $transaction_id, string $subject, int $amountCLP, string $email)
{
$response = $this->postApi($transaction_id, $subject, $amountCLP, $email);
$database = $this->saveAPIResponse($response, $transaction_id);
return redirect()->away($response['url']);
}
public function return($order)
{
$found = PaykuTransaction::whereOrder($order)->firstOrFail();
$response = $this->getApi($found);
$this->saveAPIResponse($response);
return redirect()->route('payku.notify', $order);
}
public function notify($order)
{
return PaykuTransaction::whereOrder($order)->firstOrFail();
}
public function findById($id)
{
return PaykuTransaction::whereId($id)->firstOrFail();
}
public function hasStatusSuccess($id)
{
return $this->findById($id)->status == 'success';
}
public function hasStatusPending($id)
{
return $this->findById($id)->status == 'pending';
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace SebaCarrasco93\LaravelPayku;
use Illuminate\Support\ServiceProvider;
class LaravelPaykuServiceProvider extends ServiceProvider
{
public function boot()
{
$this->loadRoutesFrom(__DIR__ . '/../routes/web.php');
$this->loadMigrationsFrom($this->basePath('database/migrations'));
$this->loadViewsFrom($this->basePath('resources/views'), 'payku');
$this->loadTranslationsFrom($this->basePath('resources/lang'), 'laravel-payku');
$this->publishes([
$this->basePath('config/laravel-payku.php') => base_path('config/laravel-payku.php')
], 'laravel-payku-config');
$this->publishes([
$this->basePath('database/migrations') => database_path('migrations')
], 'laravel-payku-migrations');
}
public function register()
{
$this->app->bind('laravel-payku', function() {
return new LaravelPayku;
});
$this->mergeConfigFrom(
$this->basePath('config/laravel-payku.php'), 'laravel-payku'
);
}
public function basePath($path = '')
{
return __DIR__ . '/../' . $path;
}
}

View File

@@ -0,0 +1,10 @@
<?php
namespace SebaCarrasco93\LaravelPayku\Models;
use Illuminate\Database\Eloquent\Model;
class PaykuPayment extends Model
{
protected $guarded = [];
}

View File

@@ -0,0 +1,43 @@
<?php
namespace SebaCarrasco93\LaravelPayku\Models;
use Illuminate\Database\Eloquent\Model;
class PaykuTransaction extends Model
{
protected $guarded = [];
public $incrementing = false;
public function payment()
{
return $this->hasOne(PaykuPayment::class, 'transaction_id');
}
public function scopeRegister($query)
{
$query->where('status', 'register');
}
public function scopeSuccess($query)
{
$query->where('status', 'success');
}
public function scopePending($query)
{
$query->where('status', 'pending');
}
public function markAsNotified()
{
return $this->update(['notified_at' => now()]);
}
public function notifyForFirstTime()
{
if (! $this->notified_at) {
return $this->markAsNotified();
}
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace SebaCarrasco93\LaravelPayku;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Route;
class RouteServiceProvider extends ServiceProvider
{
protected $namespace = 'SebaCarrasco93\LaravelPayku\Http\Controllers';
public function map()
{
Route::namespace($this->namespace)
->name('payku.')
->prefix(config('laravel-payku.route_prefix')) // "payku"
->group(__DIR__ . '/../routes/web.php');
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace SebaCarrasco93\LaravelPayku\Traits;
use SebaCarrasco93\LaravelPayku\Models\PaykuTransaction;
trait DatabaseSimulation
{
public function completeTransaction($order_id, $response)
{
$response = collect($response);
$transaction = new PaykuTransaction();
$updated_transaction = $transaction->complete($order_id, [
'status' => 'success',
'order_id' => 100,
'subject' => 'Test',
'email' => 'seba@sextanet.cl',
]);
}
public function storePayment($response)
{
$response = collect($response)->toArray();
$found = PaykuTransaction::firstWhere('order_id', $response['id']);
return $found->payment()->create($response);
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace SebaCarrasco93\LaravelPayku\Traits;
use SebaCarrasco93\LaravelPayku\Models\PaykuTransaction;
trait PrepareOrders
{
public function prepareOrder(string $order, string $subject, int $amountCLP, string $email, $paymentId = 1)
{
return [
'email' => $email,
'order' => $order,
'subject' => $subject,
'amount' => $amountCLP,
'payment' => $paymentId, // Weppay
'urlreturn' => route('payku.return', $order),
'urlnotify' => route('payku.notify', $order),
];
}
}

View File

@@ -0,0 +1,5 @@
<?php
test('example', function () {
expect(true)->toBeTrue();
});

View File

@@ -0,0 +1,35 @@
<?php
namespace SebaCarrasco93\LaravelPayku\Tests\Feature;
use SebaCarrasco93\LaravelPayku\Tests\TestCase;
class CanGetRoutesTest extends TestCase
{
public function setUp() : void
{
parent::setUp();
$this->fillApiKeys();
}
/** @test */
function it_can_create_an_order() {
$this->markTestIncomplete();
$this->withoutExceptionHanpdling();
$order = [
'email' => 'seba@sextanet.cl',
'order' => 'AAA',
'subject' => 'Test',
'amount' => '1000',
'payment' => '1',
'urlreturn' => route('payku.return', 'AAA'),
'urlnotify' => route('payku.notify', 'AAA'),
];
$this->post(route('payku.create', $order))->getContent();
$this->post(route('payku.create', $order))->assertSuccessful();
}
}

View File

@@ -0,0 +1,61 @@
<?php
namespace SebaCarrasco93\LaravelPayku\Tests\Feature;
use SebaCarrasco93\LaravelPayku\LaravelPayku;
use SebaCarrasco93\LaravelPayku\Tests\SimulateResponses;
use SebaCarrasco93\LaravelPayku\Tests\TestCase;
class CanHandleAPIResponsesTest extends TestCase
{
use SimulateResponses;
public function setUp() : void
{
parent::setUp();
$this->fillApiKeys();
$this->laravelPayku = new LaravelPayku();
}
/** @test */
function it_can_handle_when_it_has_register_status() {
$response = $this->registerResponse();
$this->laravelPayku->handleAPIResponse($response);
$this->assertEquals('register', $this->laravelPayku->status);
}
/** @test */
function it_can_handle_when_it_has_pending_status() {
$response = $this->pendingResponse();
$this->laravelPayku->handleAPIResponse($response);
$this->assertEquals('pending', $this->laravelPayku->status);
}
/** @test */
function it_can_handle_when_it_has_failed_status() {
$response = $this->failedResponse();
$this->laravelPayku->handleAPIResponse($response);
$this->assertEquals('failed', $this->laravelPayku->status);
}
/** @test */
function it_can_handle_when_it_has_success_status() {
$response = $this->successResponse();
$this->laravelPayku->handleAPIResponse($response);
$this->assertEquals('success', $this->laravelPayku->status);
}
/** @test */
function it_can_handle_an_error_when_it_has_an_invalid_status() {
$this->expectException(\Exception::class);
$response = $this->invalidResponse();
$this->laravelPayku->handleAPIResponse($response);
}
}

View File

@@ -0,0 +1,59 @@
<?php
namespace SebaCarrasco93\LaravelPayku\Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use SebaCarrasco93\LaravelPayku\LaravelPayku;
use SebaCarrasco93\LaravelPayku\Models\PaykuTransaction;
use SebaCarrasco93\LaravelPayku\Tests\SimulateResponses;
use SebaCarrasco93\LaravelPayku\Tests\TestCase;
class CanSaveAPIResponsesTest extends TestCase
{
use RefreshDatabase;
use SimulateResponses;
public function setUp() : void
{
parent::setUp();
$this->fillApiKeys();
$this->laravelPayku = new LaravelPayku();
}
/** @test */
function it_can_save_when_it_has_register_status() {
$this->laravelPayku->saveAPIResponse($this->registerResponse());
$registerStatusTransaction = PaykuTransaction::first();
$this->assertNotNull($registerStatusTransaction->id);
$this->assertNotNull($registerStatusTransaction->status);
$this->assertNotNull($registerStatusTransaction->url);
}
/** @test */
function it_can_save_when_it_has_register_status_and_passes_to_success_status() {
$this->laravelPayku->saveAPIResponse($this->registerResponse());
$registerStatusTransaction = PaykuTransaction::first();
$this->assertNull($registerStatusTransaction->order);
$this->assertNull($registerStatusTransaction->email);
$this->assertNull($registerStatusTransaction->subject);
$this->assertNull($registerStatusTransaction->amount);
$this->laravelPayku->saveAPIResponse($this->successResponse());
$registerStatusTransaction = PaykuTransaction::first();
$this->assertCount(1, PaykuTransaction::get());
$this->assertNotNull($registerStatusTransaction->id);
$this->assertNotNull($registerStatusTransaction->status);
$this->assertNotNull($registerStatusTransaction->order);
$this->assertNotNull($registerStatusTransaction->email);
$this->assertNotNull($registerStatusTransaction->subject);
$this->assertNotNull($registerStatusTransaction->url);
$this->assertNotNull($registerStatusTransaction->amount);
}
}

View File

@@ -0,0 +1,85 @@
<?php
namespace SebaCarrasco93\LaravelPayku\Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use SebaCarrasco93\LaravelPayku\LaravelPayku;
use SebaCarrasco93\LaravelPayku\Models\PaykuPayment;
use SebaCarrasco93\LaravelPayku\Models\PaykuTransaction;
use SebaCarrasco93\LaravelPayku\Tests\SimulateResponses;
use SebaCarrasco93\LaravelPayku\Tests\TestCase;
class WorkWithValidOrInvalidResponsesTest extends TestCase
{
use SimulateResponses;
use RefreshDatabase;
public function setUp() : void
{
parent::setUp();
$this->fillApiKeys();
$this->laravelPayku = new LaravelPayku();
}
/** @test */
function it_knows_when_it_has_an_valid_api_response() {
$response = $this->successResponse();
$this->laravelPayku->handleAPIResponse($response);
$this->assertTrue($this->laravelPayku->hasValidResponse);
}
/** @test */
function it_knows_when_it_does_not_have_an_valid_api_response() {
$this->expectException(\Exception::class);
$response = $this->invalidResponse();
$this->laravelPayku->handleAPIResponse($response);
$this->assertFalse($this->laravelPayku->hasValidResponse);
}
/** @test */
function it_can_create_the_pending_response_in_transactions() {
$response = $this->pendingResponse();
$this->laravelPayku->saveAPIResponse($response);
$this->assertCount(1, PaykuTransaction::get());
$this->assertCount(0, PaykuPayment::get());
}
/** @test */
function it_cannot_create_the_failed_response_in_transactions() {
$this->expectException(\Exception::class);
$response = $this->failedResponse();
$this->laravelPayku->saveAPIResponse($response);
$this->assertCount(0, PaykuTransaction::get());
$this->assertCount(0, PaykuPayment::get());
}
/** @test */
function it_can_create_the_register_response_in_transactions() {
$response = $this->registerResponse();
$this->laravelPayku->saveAPIResponse($response);
$this->assertCount(1, PaykuTransaction::get());
$this->assertCount(0, PaykuPayment::get());
}
/** @test */
function it_can_create_the_success_response_in_transactions() {
$response = $this->successResponse();
$this->laravelPayku->saveAPIResponse($response);
$this->assertCount(1, PaykuTransaction::get());
$this->assertCount(1, PaykuPayment::get());
}
}

View File

@@ -0,0 +1,45 @@
<?php
/*
|--------------------------------------------------------------------------
| Test Case
|--------------------------------------------------------------------------
|
| The closure you provide to your test functions is always bound to a specific PHPUnit test
| case class. By default, that class is "PHPUnit\Framework\TestCase". Of course, you may
| need to change it using the "uses()" function to bind a different classes or traits.
|
*/
// uses(Tests\TestCase::class)->in('Feature');
/*
|--------------------------------------------------------------------------
| Expectations
|--------------------------------------------------------------------------
|
| When you're writing tests, you often need to check that values meet certain conditions. The
| "expect()" function gives you access to a set of "expectations" methods that you can use
| to assert different things. Of course, you may extend the Expectation API at any time.
|
*/
expect()->extend('toBeOne', function () {
return $this->toBe(1);
});
/*
|--------------------------------------------------------------------------
| Functions
|--------------------------------------------------------------------------
|
| While Pest is very powerful out-of-the-box, you may have some testing code specific to your
| project that you don't want to repeat in every file. Here you can also expose helpers as
| global functions to help you to reduce the number of lines of code in your test files.
|
*/
function something()
{
// ..
}

View File

@@ -0,0 +1,95 @@
<?php
namespace SebaCarrasco93\LaravelPayku\Tests;
trait SimulateResponses
{
public function registerResponse()
{
$response = [
'status' => 'register',
'id' => 'trx...',
'url' => 'https://des.payku.cl/gateway/cobro?id=trx3adbf8e836510de62&valid=4e31d8c7c9',
];
return collect($response);
}
public function pendingResponse()
{
$response = [
'status' => 'pending',
'id' => 'trx...',
'created_at' => now(),
'order' => 1,
'email' => 'example@domain.com',
'subject' => 'Pending transaction',
'amount' => '1000',
'payment' => collect([]),
'gateway_response' => collect([
'status' => 'pending',
'message' => 'waiting response',
]),
];
return collect($response);
}
public function failedResponse()
{
$response = [
'status' => 'failed',
'type' => 'Unprocessable Entity',
'message_error' => collect([
'order' => 'invalid, max [20] characters',
]),
];
return collect($response);
}
public function successResponse()
{
$response = [
'status' => 'success',
'id' => 'trx...',
'created_at' => now(),
'order' => 1,
'email' => 'example@domain.com',
'subject' => 'Successful transaction',
'amount' => '1000',
'payment' => collect([
'start' => now(),
'end' => now()->addMinute(),
'media' => 'Webpay',
'transaction_id' => 'trx...',
'authorization_code' => '1213',
'verification_key' => '12345abcdef...',
'last_4_digits' => '6623',
'installments' => 0,
'card_type' => 'VN',
'additional_parameters' => '',
'currency' => 'CLP',
]),
'gateway_response' => collect([
'status' => 'success',
'message' => 'successful transaction',
]),
];
return collect($response);
}
public function invalidResponse()
{
$response = [
'status' => 'invalid',
'type' => '...',
'another_invalid_values' => [
'nope' => 'error',
],
];
return collect($response);
}
}

View File

@@ -0,0 +1,60 @@
<?php
namespace SebaCarrasco93\LaravelPayku\Tests;
use Orchestra\Testbench\TestCase as BaseTestCase;
use SebaCarrasco93\LaravelPayKu\LaravelPayKu as LaravelPayKuClass;
use SebaCarrasco93\LaravelPayku\LaravelPaykuServiceProvider;
use SebaCarrasco93\LaravelPayku\RouteServiceProvider;
class TestCase extends BaseTestCase
{
protected function setUp() : void
{
parent::setUp();
}
public function fillApiKeys()
{
config(['laravel-payku.public_token' => 'somepublictoken']);
config(['laravel-payku.private_token' => 'someprivatetoken']);
// config(['laravel-payku.base_url' => 'somebaseurlvalue']);
}
public function unfillApiKeys()
{
config(['laravel-payku.public_token' => null]);
config(['laravel-payku.private_token' => null]);
// config(['laravel-payku.base_url' => null]);
}
protected function getEnvironmentSetup($app)
{
$app['config']->set('database.default', 'testing');
$app['config']->set('database.conection.testing', [
'driver' => 'sqlite',
'database' => ':memory:',
]);
}
protected function getPackageProviders($app)
{
return [
LaravelPaykuServiceProvider::class,
RouteServiceProvider::class,
];
}
protected function getPackageAliases($app)
{
return [
'LaravelPayKu' => '\SebaCarrasco93\LaravelPayku\Facades\LaravelPayku::class'
];
}
public function nowIs($datetime)
{
\Carbon\Carbon::setTestNow($datetime);
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace SebaCarrasco93\LaravelPayku\Tests\Unit;
use Illuminate\Foundation\Testing\RefreshDatabase;
use SebaCarrasco93\LaravelPayku\Models\PaykuPayment;
use SebaCarrasco93\LaravelPayku\Models\PaykuTransaction;
use SebaCarrasco93\LaravelPayku\Tests\TestCase;
class LaravelPaykuDatabaseTest extends TestCase
{
use RefreshDatabase;
public function setUp() : void
{
parent::setUp();
$this->transaction = new PaykuTransaction();
}
}

View File

@@ -0,0 +1,101 @@
<?php
namespace SebaCarrasco93\LaravelPayku\Tests\Unit;
use Illuminate\Foundation\Testing\RefreshDatabase;
use SebaCarrasco93\LaravelPayku\Facades\LaravelPayku;
use SebaCarrasco93\LaravelPayku\Models\PaykuPayment;
use SebaCarrasco93\LaravelPayku\Models\PaykuTransaction;
use SebaCarrasco93\LaravelPayku\Tests\TestCase;
class LaravelPaykuFacadeTest extends TestCase
{
use RefreshDatabase;
public function setUp() : void
{
parent::setUp();
$this->fillApiKeys();
}
/** @test */
function it_knows_which_base_url_in_production_environment() {
config(['app.env' => 'production']);
$this->assertEquals('https://app.payku.cl/api', LaravelPayku::apiRoute());
}
/** @test */
function it_knows_which_base_url_in_local_and_testing_environment() {
config(['app.env' => 'local']);
$this->assertEquals('https://des.payku.cl/api', LaravelPayku::apiRoute());
config(['app.env' => 'testing']);
$this->assertEquals('https://des.payku.cl/api', LaravelPayku::apiRoute());
}
/** @test */
function it_can_override_the_base_url() {
config(['app.env' => 'production']);
config(['laravel-payku.base_url' => 'https://des.payku.cl/api']);
$this->assertEquals('https://des.payku.cl/api', LaravelPayku::apiRoute());
}
/** @test */
function it_knows_only_its_filled_keys() {
$this->assertEquals([
'private_token' => 'someprivatetoken',
'public_token' => 'somepublictoken',
], LaravelPayku::findApiKeys());
}
/** @test */
function it_knows_when_does_has_the_required_keys() {
$this->assertTrue(LaravelPayku::hasValidConfig());
}
/** @test */
function it_knows_when_does_not_have_the_required_keys() {
$this->expectException(\Exception::class);
$this->unfillApiKeys();
LaravelPayku::hasValidConfig();
}
/** @test */
function it_can_prepare_an_order() {
$this->assertEquals([
'email' => 'seba@sextanet.cl',
'order' => 'AAA',
'subject' => 'Test',
'amount' => '1000',
'payment' => '1',
'urlreturn' => route('payku.return', 'AAA'),
'urlnotify' => route('payku.notify', 'AAA'),
], LaravelPayku::prepareOrder('AAA', 'Test', 1000, 'seba@sextanet.cl'));
}
/** @test */
function it_knows_its_details() {
$payment = PaykuTransaction::create(['id' => 'trx...']);
$this->assertInstanceOf(PaykuTransaction::class, LaravelPayku::findById('trx...'));
}
/** @test */
function it_knows_when_it_has_status_success() {
$payment = PaykuTransaction::create(['id' => 'trx...', 'status' => 'success']);
$this->assertTrue(LaravelPayku::hasStatusSuccess('trx...'));
$this->assertFalse(LaravelPayku::hasStatusPending('trx...'));
}
/** @test */
function it_knows_when_it_has_status_pending() {
$payment = PaykuTransaction::create(['id' => 'trx...', 'status' => 'pending']);
$this->assertTrue(LaravelPayku::hasStatusPending('trx...'));
$this->assertFalse(LaravelPayku::hasStatusSuccess('trx...'));
}
}

View File

@@ -0,0 +1,68 @@
<?php
namespace SebaCarrasco93\LaravelPayku\Tests\Unit;
use SebaCarrasco93\LaravelPayku\Tests\TestCase;
use SebaCarrasco93\LaravelPayku\Models\PaykuTransaction;
use Illuminate\Foundation\Testing\RefreshDatabase;
class PaykuTransactionTest extends TestCase
{
use RefreshDatabase;
/** @test */
function it_can_see_their_id() {
$transaction = PaykuTransaction::create(['id' => 'trx...']);
$this->assertEquals('trx...', $transaction->id);
}
/** @test */
function it_can_get_only_transactions_with_status_register() {
$transaction = PaykuTransaction::create(['id' => 'trx...', 'status' => 'register']);
$this->assertCount(1, PaykuTransaction::register()->get());
}
/** @test */
function it_can_get_only_transactions_with_status_success() {
$transaction = PaykuTransaction::create(['id' => 'trx...', 'status' => 'success']);
$this->assertCount(1, PaykuTransaction::success()->get());
}
/** @test */
function it_can_get_only_transactions_with_status_pending() {
$transaction = PaykuTransaction::create(['id' => 'trx...', 'status' => 'pending']);
$this->assertCount(1, PaykuTransaction::pending()->get());
}
/** @test */
function it_knows_when_it_was_marked_as_notified() {
$transaction = PaykuTransaction::create(['id' => 'trx...', 'notified_at' => null]);
$transaction->markAsNotified();
$this->assertNotNull($transaction->notified_at);
}
/** @test */
function it_can_notify_for_first_time() {
$transaction = PaykuTransaction::create(['id' => 'trx...', 'notified_at' => null]);
$this->nowIs('2021-07-26');
$now = now();
$transaction->notifyForFirstTime();
$this->assertEquals($now->format('Y-m-d'), $transaction->notified_at->format('Y-m-d'));
$transaction->notifyForFirstTime();
$this->nowIs('2021-07-30');
$this->assertNotEquals('2021-07-30', $transaction->notified_at->format('Y-m-d'));
}
}