diff --git a/README.md b/README.md index 987a8f5..05492a5 100644 --- a/README.md +++ b/README.md @@ -4,14 +4,14 @@ Płatności PayU w Laravel. Jak utworzyć link do płatności za zamówienie w p ## Payu dokumentacja, sandbox -https://developers.payu.com/pl/overview.html#sandbox + ## Instalacja pakietu Laravela -Zainstaluj php composera ze strony https://getcomposer.org/download +Zainstaluj php composera ze strony ```sh -composer require atomjoy/payu 2.0.* +composer require atomjoy/payu "^3.0.0" composer update composer dump-autoload -o ``` @@ -27,6 +27,13 @@ CREATE DATABASE IF NOT EXISTS laravel CHARACTER SET utf8mb4 COLLATE utf8mb4_unic GRANT ALL PRIVILEGES ON laravel.* TO root@localhost IDENTIFIED BY 'toor' WITH GRANT OPTION; GRANT ALL PRIVILEGES ON laravel.* TO root@127.0.0.1 IDENTIFIED BY 'toor' WITH GRANT OPTION; FLUSH PRIVILEGES; + +# Clear or change password +SET PASSWORD FOR root@localhost=PASSWORD(''); + +# Change password +ALTER USER 'testing'@'localhost' IDENTIFIED BY 'toor'; +FLUSH PRIVILEGES; ``` ### Konfiguracja .env @@ -46,7 +53,9 @@ DB_PASSWORD=toor php artisan make:model Order -a ``` -### Dodaj kolumny w tabeli +### Migracja tabeli klasy Order + +Dodaj kolumny w tabeli. ```php id(); - $table->decimal('cost', 15, 2)->nullable()->default(0.00); - $table->enum('payment_method', ['money', 'card', 'online'])->nullable()->default('money'); - $table->enum('payment_gateway', ['payu'])->nullable(true); - $table->string('firstname'); - $table->string('lastname'); - $table->string('phone'); - $table->string('email'); - $table->timestamps(); - $table->softDeletes(); - $table->unsignedBigInteger('user_id')->nullable(true); - $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade')->onUpdate('cascade'); - }); - } - - public function down() - { - Schema::dropIfExists('orders'); - } + public function up() + { + Schema::create('orders', function (Blueprint $table) { + $table->id(); + $table->decimal('cost', 15, 2)->nullable()->default(0.00); + $table->enum('payment_method', ['money', 'card', 'online', 'cashback'])->nullable()->default('money'); + $table->enum('payment_gateway', ['payu'])->nullable(true); + $table->string('firstname'); + $table->string('lastname'); + $table->string('phone'); + $table->string('email'); + $table->timestamps(); + $table->softDeletes(); + $table->unsignedBigInteger('user_id')->nullable(true); + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade')->onUpdate('cascade'); + }); + } + + public function down() + { + Schema::dropIfExists('orders'); + } }; ``` @@ -113,32 +122,32 @@ class Order extends Model implements PayuOrderInterface } // Wymagane metody poniżej - function order_id() + function orderId() { return $this->id; } - function order_cost() + function orderCost() { return $this->cost; } - function order_firstname() + function orderFirstname() { return $this->firstname; } - function order_lastname() + function orderLastname() { return $this->lastname; } - function order_phone() + function orderPhone() { return $this->phone; } - function order_email() + function orderEmail() { return $this->email; } @@ -161,7 +170,7 @@ config/payu.php php artisan vendor:publish --tag=payu-config ``` -### Aktualizacja cache dir linux (if errors) +### Aktualizacja cache dir linux (gdy błędy) ```sh sudo mkdir -p storage/framework/cache/payu @@ -185,23 +194,25 @@ public/vendor/payu php artisan vendor:publish --tag=payu-public --force ``` -## Testuj +## Testy ### Dodaj w phpunit.xml ```xml - ./vendor/atomjoy/payu/tests/Payu + ./vendor/atomjoy/payu/tests/Payu ``` -### Tests only with config(['payu.env' => 'sandbox']) +### Tests tylko dla sandbox config(['payu.env' => 'sandbox']) + +Utworzy link do płatności w bazie danych w tabeli payments (do przekierowania klienta sklepu). ```sh php artisan test --testsuite=Payu --stop-on-failure ``` -# Laravel PayU Api +## Laravel PayU Api Wyłączyć w panelu administracyjnym PayU automatyczny odbiór płatności jeśli chcesz potwierdzać płatności ręcznie dla statusu WAITING_FOR_CONFIRMATION na COMPLETED lub CANCELED. @@ -210,9 +221,10 @@ Wyłączyć w panelu administracyjnym PayU automatyczny odbiór płatności jeś Numer zamówienia {orders.id} => 1, 2, 3, ... ```sh -# Utwórz zamowienie a następnie +# Utwórz zamowienie i link do płatności +https://{your.domain.here}/web/payment/create -# Utwórz link do płatności +# Lub utwórz link do płatności z id zamówienia https://{your.domain.here}/web/payment/url/payu/{orders.id} # Pobierz dane płatności @@ -230,9 +242,9 @@ https://{your.domain.here}/web/payment/cancel/payu/{orders.id} ### Lista routes do obsługi płatności (sandbox) -atomjoy/payu/routes/admin.php +atomjoy/payu/routes/sandbox.php -# Przykłady Api w Php +## Przykłady Payu Api w Laravel ### Utwórz link płatności dla zamówienia (produkcja) @@ -242,6 +254,7 @@ use App\Models\Order; use Payu\Facades\Payu; try { + // Create order here or get from db with id $id = 'orders.id'; @@ -251,8 +264,12 @@ try { // Redirect client to payment page return redirect($url); -} catch (\Exception $e) { - return $e->getMessage(); +} catch (QueryException | PDOException $e) { + report($e); + return response('Database Error.', 422); +} catch (Exception $e) { + report($e); + return response($e->getMessage(), 422); } ``` @@ -382,29 +399,25 @@ try { } ``` -## Eventy Payu +## Zdarzenia Payu (events) ```php orderBy('created_at', 'desc')->get(); diff --git a/config/config.php b/config/config.php index a64cb40..3fba488 100644 --- a/config/config.php +++ b/config/config.php @@ -1,23 +1,6 @@ true, - - // Load payu routes - 'routes' => true, - - // Load payu db migrations - 'migrations' => true, - - // Enable payu logs - 'logs' => [ - 'notify' => false, - 'errors' => true, - ], - - // Payu api credentials - // Set environment: 'sandbox' or 'secure' 'env' => 'sandbox', @@ -30,5 +13,16 @@ 'client_secret' => '', // Currency - 'currency' => 'PLN' + 'currency' => 'PLN', + + // Settings + + // Enable payu payments + 'enable' => true, + + // Load payu routes + 'routes' => true, + + // Load payu db migrations + 'migrations' => true, ]; diff --git a/database/factories/.gitkeep b/database/factories/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/database/factories/PayuLogFactory.php b/database/factories/PayuLogFactory.php deleted file mode 100644 index 618e08a..0000000 --- a/database/factories/PayuLogFactory.php +++ /dev/null @@ -1,21 +0,0 @@ - 'err_' . $this->faker->uuid(), - 'description' => $this->faker->sentence(), - 'oid' => '', - 'ip' => request()->ip(), - ]; - } -} diff --git a/database/migrations/9000_12_31_1_create_orders_table.php b/database/migrations/9000_12_31_1_create_orders_table.php new file mode 100644 index 0000000..57bcfc9 --- /dev/null +++ b/database/migrations/9000_12_31_1_create_orders_table.php @@ -0,0 +1,43 @@ +id(); + $table->enum('payment_method', ['money', 'card', 'online', 'cashback'])->nullable()->default('money'); + $table->enum('payment_gateway', ['payu'])->nullable(true); + $table->decimal('cost', 15, 2)->nullable()->default(0.00); + $table->string('firstname'); + $table->string('lastname'); + $table->string('phone'); + $table->string('email'); + $table->timestamps(); + $table->softDeletes(); + $table->unsignedBigInteger('user_id')->nullable(true); + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade')->onUpdate('cascade'); + }); + } + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('orders'); + } +}; diff --git a/database/migrations/9000_12_31_1_create_payments_table.php b/database/migrations/9000_12_31_2_create_payments_table.php similarity index 92% rename from database/migrations/9000_12_31_1_create_payments_table.php rename to database/migrations/9000_12_31_2_create_payments_table.php index 7019d67..1088b4e 100644 --- a/database/migrations/9000_12_31_1_create_payments_table.php +++ b/database/migrations/9000_12_31_2_create_payments_table.php @@ -4,7 +4,7 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class CreatePaymentsTable extends Migration +return new class extends Migration { /** * Run the migrations. @@ -27,7 +27,7 @@ public function up() $table->timestamps(); $table->softDeletes(); - $table->unsignedBigInteger('order_id')->index(); + $table->unsignedBigInteger('order_id'); $table->foreign('order_id')->references('id')->on('orders')->onUpdate('cascade')->onDelete('cascade'); }); } @@ -41,4 +41,4 @@ public function down() { Schema::dropIfExists('payments'); } -} +}; diff --git a/database/migrations/9000_12_31_2_create_payu_logs_table.php b/database/migrations/9000_12_31_2_create_payu_logs_table.php deleted file mode 100644 index d8deb5f..0000000 --- a/database/migrations/9000_12_31_2_create_payu_logs_table.php +++ /dev/null @@ -1,36 +0,0 @@ -id(); - $table->string('code'); - $table->text('description'); - $table->string('oid'); - $table->string('ip')->nullable(true); - $table->timestamps(); - $table->softDeletes(); - }); - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::dropIfExists('payu_logs'); - } -}; diff --git a/database/seeders/PayuDatabaseSeeder.php b/database/seeders/PayuDatabaseSeeder.php index 7f7a659..e5b2afc 100644 --- a/database/seeders/PayuDatabaseSeeder.php +++ b/database/seeders/PayuDatabaseSeeder.php @@ -15,8 +15,6 @@ public function run() { // \App\Models\User::factory(30)->create(); - $this->call([ - PayuLogSeeder::class, - ]); + $this->call([]); } } diff --git a/database/seeders/PayuLogSeeder.php b/database/seeders/PayuLogSeeder.php deleted file mode 100644 index 9acc738..0000000 --- a/database/seeders/PayuLogSeeder.php +++ /dev/null @@ -1,19 +0,0 @@ -count(5)->create(); - } -} diff --git a/routes/admin.php b/routes/sandbox.php similarity index 92% rename from routes/admin.php rename to routes/sandbox.php index 18a0675..3348f17 100644 --- a/routes/admin.php +++ b/routes/sandbox.php @@ -1,38 +1,41 @@ -name('web.')->middleware(['web', 'payu'])->group(function () { - // Create payu payment url from order - Route::get('/payment/url/payu/{order}', [PayuPaymentController::class, 'pay']) - ->name('payu.url'); - // Confirm waiting payu payment (disable auto confirmation in payu panel) - Route::get('/payment/confirm/payu/{order}', [PayuPaymentController::class, 'confirm']) - ->name('payu.confirm'); - // Cancel waiting payu payment (disable auto confirmation in payu panel) - Route::get('/payment/cancel/payu/{order}', [PayuPaymentController::class, 'cancel']) - ->name('payu.cancel'); - // Refresh payu payment details - Route::get('/payment/refresh/payu/{order}', [PayuPaymentController::class, 'refresh']) - ->name('payu.refresh'); - // Get payment details - Route::get('/payment/retrive/payu/{order}', [PayuPaymentController::class, 'retrive']) - ->name('payu.retrive'); - // Get payment transaction details - Route::get('/payment/transaction/payu/{order}', [PayuPaymentController::class, 'transaction']) - ->name('payu.transaction'); - // Refund payment - Route::get('/payment/refund/payu/{order}', [PayuPaymentController::class, 'refund']) - ->name('payu.refund'); - // Get refunds details - Route::get('/payment/refunds/payu/{order}', [PayuPaymentController::class, 'refunds']) - ->name('payu.refunds'); - // Get allowed payment types list - Route::get('/payment/payments/payu/{lang}', [PayuPaymentController::class, 'payments']) - ->name('payu.payments'); - }); -} +name('web.')->middleware(['web', 'payu'])->group(function () { + // Create order with payment link + Route::get('/payment/create', [PayuPaymentController::class, 'create']) + ->name('payu.create'); + // Create payu payment url from order + Route::get('/payment/url/payu/{order}', [PayuPaymentController::class, 'pay']) + ->name('payu.url'); + // Confirm waiting payu payment (disable auto confirmation in payu panel) + Route::get('/payment/confirm/payu/{order}', [PayuPaymentController::class, 'confirm']) + ->name('payu.confirm'); + // Cancel waiting payu payment (disable auto confirmation in payu panel) + Route::get('/payment/cancel/payu/{order}', [PayuPaymentController::class, 'cancel']) + ->name('payu.cancel'); + // Refresh payu payment details + Route::get('/payment/refresh/payu/{order}', [PayuPaymentController::class, 'refresh']) + ->name('payu.refresh'); + // Get payment details + Route::get('/payment/retrive/payu/{order}', [PayuPaymentController::class, 'retrive']) + ->name('payu.retrive'); + // Get payment transaction details + Route::get('/payment/transaction/payu/{order}', [PayuPaymentController::class, 'transaction']) + ->name('payu.transaction'); + // Refund payment + Route::get('/payment/refund/payu/{order}', [PayuPaymentController::class, 'refund']) + ->name('payu.refund'); + // Get refunds details + Route::get('/payment/refunds/payu/{order}', [PayuPaymentController::class, 'refunds']) + ->name('payu.refunds'); + // Get allowed payment types list + Route::get('/payment/payments/payu/{lang}', [PayuPaymentController::class, 'payments']) + ->name('payu.payments'); + }); +} diff --git a/routes/web.php b/routes/web.php index 5206848..2b207dd 100644 --- a/routes/web.php +++ b/routes/web.php @@ -20,4 +20,4 @@ }); // Private routes -require('admin.php'); +require('sandbox.php'); diff --git a/src/Events/PayuPaymentNotCreated.php b/src/Events/PayuPaymentNotCreated.php deleted file mode 100644 index 8386c2b..0000000 --- a/src/Events/PayuPaymentNotCreated.php +++ /dev/null @@ -1,28 +0,0 @@ -order = $order; - } -} diff --git a/src/Gateways/PayuPaymentGateway.php b/src/Gateways/PayuPaymentGateway.php index 850cd46..4d572ce 100644 --- a/src/Gateways/PayuPaymentGateway.php +++ b/src/Gateways/PayuPaymentGateway.php @@ -5,17 +5,17 @@ use Exception; use App\Models\Order; use Illuminate\Support\Str; -use Payu\Interfaces\PayuGatewayInterface; -use Payu\Interfaces\PayuGatewayAbstract; -use Payu\Models\Payment; -use Payu\Models\PayuLog; +use Illuminate\Support\Facades\Log; use Payu\Events\PayuPaymentCreated; -use Payu\Events\PayuPaymentNotCreated; use Payu\Events\PayuPaymentCanceled; use Payu\Events\PayuPaymentConfirmed; use Payu\Events\PayuPaymentRefunded; use Payu\Events\PayuPaymentNotified; +use Payu\Interfaces\PayuGatewayAbstract; +use Payu\Interfaces\PayuGatewayInterface; +use Payu\Interfaces\PayuOrderInterface; use Payu\Http\Payu\OpenPayU_Refunds; +use Payu\Models\Payment; use OpenPayU_Configuration; use OpenPayU_Order; use OpenPayU_Refund; @@ -25,7 +25,6 @@ use OpenPayU_Exception; use OpenPayU_Util; use OpenPayU; -use Payu\Interfaces\PayuOrderInterface; /** * PayU payment gateway @@ -63,29 +62,24 @@ function __construct() function config() { - try { - // Cache - OpenPayU_Configuration::setOauthTokenCache( - new OauthCacheFile(storage_path() . '/framework/cache/payu') - ); - - // Environment - OpenPayU_Configuration::setEnvironment($this->env); - - if (!empty($this->pos_id)) { - // POS ID and Second MD5 Key (from merchant admin panel) - OpenPayU_Configuration::setMerchantPosId($this->pos_id); - OpenPayU_Configuration::setSignatureKey($this->pos_md5); - } + // Cache + OpenPayU_Configuration::setOauthTokenCache( + new OauthCacheFile(storage_path() . '/framework/cache/payu') + ); + + // Environment + OpenPayU_Configuration::setEnvironment($this->env); + + if (!empty($this->pos_id)) { + // POS ID and Second MD5 Key (from merchant admin panel) + OpenPayU_Configuration::setMerchantPosId($this->pos_id); + OpenPayU_Configuration::setSignatureKey($this->pos_md5); + } - if (!empty($this->client_id)) { - // Oauth Client Id and Oauth Client Secret (from merchant admin panel) - OpenPayU_Configuration::setOauthClientId($this->client_id); - OpenPayU_Configuration::setOauthClientSecret($this->client_secret); - } - } catch (Exception $e) { - $this->log('PAYU_CONFIG_ERR', $e->getMessage()); - throw new Exception($e->getMessage(), 422); + if (!empty($this->client_id)) { + // Oauth Client Id and Oauth Client Secret (from merchant admin panel) + OpenPayU_Configuration::setOauthClientId($this->client_id); + OpenPayU_Configuration::setOauthClientSecret($this->client_secret); } } @@ -93,385 +87,346 @@ function pay(PayuOrderInterface $order): string { $payu_url = ''; - try { - // Payment - $payment = Payment::create([ - 'id' => Str::uuid(), - 'order_id' => $order->order_id(), - ]); - - // Client address - $total = $this->toCents((float) $order->order_cost()); - $desc = 'ID-' . $order->order_id(); - // Credentials - $o['merchantPosId'] = OpenPayU_Configuration::getMerchantPosId(); - // Urls - $o['notifyUrl'] = $this->notifyUrl(); - $o['continueUrl'] = $this->successUrl($order); - // Order uid string - $o['extOrderId'] = $payment->id; - $o['currencyCode'] = $this->currency; - $o['customerIp'] = $this->ipAddress(); - $o['totalAmount'] = $total; - $o['description'] = $desc; - // Products - $o['products'][0]['name'] = $desc; - $o['products'][0]['unitPrice'] = $total; - $o['products'][0]['quantity'] = 1; - // Buyer - $o['buyer']['email'] = $order->order_email(); - $o['buyer']['phone'] = $order->order_phone(); - $o['buyer']['firstName'] = $order->order_firstname(); - $o['buyer']['lastName'] = $order->order_lastname(); - $o['buyer']['language'] = $this->lang(); - - // Create payu order - $res = OpenPayU_Order::create($o); - - if (!$res instanceof OpenPayU_Result || $res->getStatus() != 'SUCCESS') { - throw new Exception('Invalid payment object or status'); - } - - $payu_uid = $res->getResponse()->orderId ?? null; - $payu_url = $res->getResponse()->redirectUri ?? null; - - if (empty($payu_uid) || empty($payu_url)) { - throw new Exception('Invalid payment details'); - } - - $a = [ - 'payu_id' => $payu_uid, - 'url' => $payu_url, - 'total' => $total, - 'cost' => $order->order_cost(), - 'currency' => $this->currency, - 'ip' => $this->ipAddress(), - 'gateway' => 'payu' - ]; - - $payment->fill($a); - $payment->save(); - - // Emit event - PayuPaymentCreated::dispatch($order); - - return $payu_url; - } catch (Exception $e) { - $this->log('PAYU_PAY_ERR', $e->getMessage(), $order->order_id()); - PayuPaymentNotCreated::dispatch($order); - return $e->getMessage(); + // Payment + $payment = Payment::create([ + 'id' => Str::uuid(), + 'order_id' => $order->orderId(), + ]); + + // Client address + $total = $this->toCents((float) $order->orderCost()); + $desc = 'ID-' . $order->orderId(); + // Credentials + $o['merchantPosId'] = OpenPayU_Configuration::getMerchantPosId(); + // Urls + $o['notifyUrl'] = $this->notifyUrl(); + $o['continueUrl'] = $this->successUrl($order); + // Order uid string + $o['extOrderId'] = $payment->id; + $o['currencyCode'] = $this->currency; + $o['customerIp'] = $this->ipAddress(); + $o['totalAmount'] = $total; + $o['description'] = $desc; + // Products + $o['products'][0]['name'] = $desc; + $o['products'][0]['unitPrice'] = $total; + $o['products'][0]['quantity'] = 1; + // Buyer + $o['buyer']['email'] = $order->orderEmail(); + $o['buyer']['phone'] = $order->orderPhone(); + $o['buyer']['firstName'] = $order->orderFirstname(); + $o['buyer']['lastName'] = $order->orderLastname(); + $o['buyer']['language'] = $this->lang(); + + // Create payu order + $res = OpenPayU_Order::create($o); + + if (!$res instanceof OpenPayU_Result || $res->getStatus() != 'SUCCESS') { + throw new Exception('Invalid payment object or status'); } - } - - function notify() - { - try { - if (!in_array($this->ipAddress(), $this->allowed_ip)) { - throw new Exception('Notify invalid ip address', 422); - } - // Data - $data = trim(request()->getContent()); - - if (empty($data)) { - throw new Exception('Notify invalid data'); - } - - // Log to database in sandbox mode - if ( - $this->env == 'sandbox' || - config('payu.logs.notify', false) == true - ) { - $this->log('PAYU_NOTIFY_CONTENT', $data); - } - - // Notification - $notify = OpenPayU_Order::consumeNotification($data); + $payu_uid = $res->getResponse()->orderId ?? null; + $payu_url = $res->getResponse()->redirectUri ?? null; - if (!$notify instanceof OpenPayU_Result) { - throw new Exception("Notify invalid object"); - } + if (empty($payu_uid) || empty($payu_url)) { + throw new Exception('Invalid payment details'); + } - PayuPaymentNotified::dispatch($notify); + $a = [ + 'payu_id' => $payu_uid, + 'url' => $payu_url, + 'total' => $total, + 'cost' => $order->orderCost(), + 'currency' => $this->currency, + 'ip' => $this->ipAddress(), + 'gateway' => 'payu' + ]; - // Confirm Order - if (!empty($notify->getResponse()->order->extOrderId)) { - $p = Payment::where('id', $notify->getResponse()->order->extOrderId)->first(); - if ($p instanceof Payment) { - $this->refresh(Order::find($p->order_id)); - return response("Comfirmed", 200); - } - } + $payment->fill($a); + $payment->save(); - // Confirm Refund - if (!empty($notify->getResponse()->refund) && !empty($notify->getResponse()->extOrderId)) { - $p = Payment::where('id', $notify->getResponse()->extOrderId)->first(); - if ($p instanceof Payment) { - $this->refunds(Order::find($p->order_id)); - return response("Comfirmed", 200); - } - } + // Emit event + PayuPaymentCreated::dispatch($order); - // Invalid notification content - throw new Exception("Invalid notification content"); - } catch (Exception $e) { - $this->log('PAYU_NOTIFY_ERR', $e->getMessage()); - return response("Not comfirmed", 422); - } + return $payu_url; } function confirm(PayuOrderInterface $order): string { - try { - $p = Payment::where(['order_id' => $order->order_id()])->latest()->first(); + $p = Payment::where(['order_id' => $order->orderId()])->latest()->first(); - if ($p instanceof Payment) { - if (!in_array($p->status, ['WAITING_FOR_CONFIRMATION'])) { - throw new Exception('You can not update payment with this status'); - } + if ($p instanceof Payment) { + if (!in_array($p->status, ['WAITING_FOR_CONFIRMATION'])) { + throw new Exception('You can not update payment with this status'); + } - $res = OpenPayU_Order::statusUpdate([ - "orderId" => $p->payu_id, - "orderStatus" => 'COMPLETED' - ]); + $res = OpenPayU_Order::statusUpdate([ + "orderId" => $p->payu_id, + "orderStatus" => 'COMPLETED' + ]); - if ($res->getStatus() == 'SUCCESS') { - // Emit event - PayuPaymentConfirmed::dispatch($order); + if ($res->getStatus() == 'SUCCESS') { + // Emit event + PayuPaymentConfirmed::dispatch($order); - return 'UPDATED'; - } else { - throw new Exception('Status update error'); - } + return 'UPDATED'; } else { - throw new Exception('Invalid payment id'); + throw new Exception('Status update error'); } - } catch (Exception $e) { - $this->log('PAYU_CONFIRM_ERR', $e->getMessage(), $order->order_id()); - return $e->getMessage(); + } else { + throw new Exception('Invalid payment id'); } } function cancel(PayuOrderInterface $order): string { - try { - $p = Payment::where(['order_id' => $order->order_id()])->latest()->first(); + $p = Payment::where(['order_id' => $order->orderId()])->latest()->first(); - if ($p instanceof Payment) { - if (!in_array($p->status, ['WAITING_FOR_CONFIRMATION'])) { - throw new Exception('You can not update payment with this status'); - } + if ($p instanceof Payment) { + if (!in_array($p->status, ['WAITING_FOR_CONFIRMATION'])) { + throw new Exception('You can not update payment with this status'); + } - $res = OpenPayU_Order::cancel($p->payu_id); + $res = OpenPayU_Order::cancel($p->payu_id); - if ($res->getStatus() == 'SUCCESS') { - if (!empty($res->getResponse()->orderId)) { - // Emit event - PayuPaymentCanceled::dispatch($order); + if ($res->getStatus() == 'SUCCESS') { + if (!empty($res->getResponse()->orderId)) { + // Emit event + PayuPaymentCanceled::dispatch($order); - return 'UPDATED'; - } - } else { - throw new Exception('Status update error'); + return 'UPDATED'; } } else { - throw new Exception('Invalid payment id or status'); + throw new Exception('Status update error'); } - } catch (Exception $e) { - $this->log('PAYU_CANCEL_ERR', $e->getMessage(), $order->order_id()); - return $e->getMessage(); + } else { + throw new Exception('Invalid payment id or status'); } } function refund(PayuOrderInterface $order): string { - try { - $p = Payment::where(['order_id' => $order->order_id()])->latest()->first(); + $p = Payment::where(['order_id' => $order->orderId()])->latest()->first(); - if ($p instanceof Payment) { - // Refund full order - $res = OpenPayU_Refund::create($p->payu_id, __('Refunding'), null); + if ($p instanceof Payment) { + // Refund full order + $res = OpenPayU_Refund::create($p->payu_id, __('Refunding'), null); - if ($res->getStatus() == 'SUCCESS') { - if ($res->getResponse()->refund->status == 'PENDING') { - $p->status_refund = 'PENDING'; - $p->save(); + if ($res->getStatus() == 'SUCCESS') { + if ($res->getResponse()->refund->status == 'PENDING') { + $p->status_refund = 'PENDING'; + $p->save(); - // Emit event - PayuPaymentRefunded::dispatch($order); + // Emit event + PayuPaymentRefunded::dispatch($order); - return 'PENDING'; - } else { - throw new Exception('Order has not been refunded'); - } + return 'PENDING'; } else { throw new Exception('Order has not been refunded'); } } else { - throw new Exception('Invalid payment id'); + throw new Exception('Order has not been refunded'); } - } catch (Exception $e) { - $this->log('PAYU_REFUND_ERR', $e->getMessage(), $order->order_id()); - return $e->getMessage(); + } else { + throw new Exception('Invalid payment id'); } } function refunds(PayuOrderInterface $order) { - try { - $p = Payment::where(['order_id' => $order->order_id()])->latest()->first(); + $p = Payment::where(['order_id' => $order->orderId()])->latest()->first(); + + if ($p instanceof Payment) { + // Get refunds from payu + $res = OpenPayU_Refunds::retrive($p->payu_id); - if ($p instanceof Payment) { - // Get refunds from payu - $res = OpenPayU_Refunds::retrive($p->payu_id); + if ( + $res instanceof OpenPayU_Result || + $res->getStatus() == 'SUCCESS' + ) { + if (empty($res->getResponse()->refunds[0])) { + throw new Exception("Empty refunds list"); + } + + $payu_refund = $res->getResponse()->refunds[0]; if ( - $res instanceof OpenPayU_Result || - $res->getStatus() == 'SUCCESS' + !is_object($payu_refund) || + empty($payu_refund->status) ) { - if (empty($res->getResponse()->refunds[0])) { - throw new Exception("Empty refunds list"); - } - - $payu_refund = $res->getResponse()->refunds[0]; - - if ( - !is_object($payu_refund) || - empty($payu_refund->status) - ) { - throw new Exception("Invalid refund details"); - } - - // Validate status - if (in_array($payu_refund->status, $this->allowed_status)) { - // Update shop payment - $p->status_refund = strtoupper($payu_refund->status); - $p->save(); - - return $res->getResponse(); - } else { - throw new Exception('Invalid refund status'); - } + throw new Exception("Invalid refund details"); + } + + // Validate status + if (in_array($payu_refund->status, $this->allowed_status)) { + // Update shop payment + $p->status_refund = strtoupper($payu_refund->status); + $p->save(); + + return $res->getResponse(); } else { throw new Exception('Invalid refund status'); } } else { - throw new Exception('Invalid refund id'); + throw new Exception('Invalid refund status'); } - } catch (Exception $e) { - $this->log('PAYU_REFUNDS_ERR', $e->getMessage(), $order->order_id()); - return $e->getMessage(); + } else { + throw new Exception('Invalid refund id'); } } function refresh(PayuOrderInterface $order): string { - try { - $p = Payment::where(['order_id' => $order->order_id()])->latest()->first(); + $p = Payment::where(['order_id' => $order->orderId()])->latest()->first(); + + if ($p instanceof Payment) { + // Get payment from payu + $res = OpenPayU_Order::retrieve($p->payu_id); + + if ( + $res instanceof OpenPayU_Result || + $res->getStatus() == 'SUCCESS' + ) { + if (empty($res->getResponse()->orders[0])) { + throw new Exception("Empty payment orders array"); + } - if ($p instanceof Payment) { - // Get payment from payu - $res = OpenPayU_Order::retrieve($p->payu_id); + $payu_order = $res->getResponse()->orders[0]; if ( - $res instanceof OpenPayU_Result || - $res->getStatus() == 'SUCCESS' + !is_object($payu_order) || + empty($payu_order->status) || + empty($payu_order->totalAmount) || + empty($payu_order->currencyCode) ) { - if (empty($res->getResponse()->orders[0])) { - throw new Exception("Empty payment orders array"); - } - - $payu_order = $res->getResponse()->orders[0]; - - if ( - !is_object($payu_order) || - empty($payu_order->status) || - empty($payu_order->totalAmount) || - empty($payu_order->currencyCode) - ) { - throw new Exception("Invalid payment details"); - } - - // Validate status - if (in_array($payu_order->status, $this->allowed_status)) { - // Update shop payment - $p->status = strtoupper($payu_order->status); - $p->currency = $payu_order->currencyCode; - $p->total = $payu_order->totalAmount; - $p->save(); - - // Return order status - return $payu_order->status; - } else { - throw new Exception('Invalid order status'); - } + throw new Exception("Invalid payment details"); + } + + // Validate status + if (in_array($payu_order->status, $this->allowed_status)) { + // Update shop payment + $p->status = strtoupper($payu_order->status); + $p->currency = $payu_order->currencyCode; + $p->total = $payu_order->totalAmount; + $p->save(); + + // Return order status + return $payu_order->status; } else { - throw new Exception('Invalid payment status'); + throw new Exception('Invalid order status'); } } else { - throw new Exception('Invalid payment id'); + throw new Exception('Invalid payment status'); } - } catch (Exception $e) { - $this->log('PAYU_REFRESH_ERR', $e->getMessage(), $order->order_id()); - return $e->getMessage(); + } else { + throw new Exception('Invalid payment id'); } } function retrive(PayuOrderInterface $order) { - try { - $p = Payment::where(['order_id' => $order->order_id()])->latest()->first(); + $p = Payment::where(['order_id' => $order->orderId()])->latest()->first(); - if ($p instanceof Payment) { - $res = OpenPayU_Order::retrieve($p->payu_id); + if ($p instanceof Payment) { + $res = OpenPayU_Order::retrieve($p->payu_id); - if ($res->getStatus() == 'SUCCESS') { - if (count($res->getResponse()->orders) == 0) { - throw new Exception("Empty orders array"); - } - - return $res->getResponse()->orders[0]; + if ($res->getStatus() == 'SUCCESS') { + if (count($res->getResponse()->orders) == 0) { + throw new Exception("Empty orders array"); } - } else { - throw new Exception('Invalid payment id'); + + return $res->getResponse()->orders[0]; } - } catch (Exception $e) { - $this->log('PAYU_RETRIVE_ERR', $e->getMessage(), $order->order_id()); - return $e->getMessage(); + } else { + throw new Exception('Invalid payment id'); } } function transaction(PayuOrderInterface $order) { - try { - $p = Payment::where(['order_id' => $order->order_id()])->latest()->first(); + $p = Payment::where(['order_id' => $order->orderId()])->latest()->first(); - if ($p instanceof Payment) { - $res = OpenPayU_Order::retrieveTransaction($p->payu_id); + if ($p instanceof Payment) { + $res = OpenPayU_Order::retrieveTransaction($p->payu_id); - if (count($res->getResponse()->transactions) == 0) { - throw new Exception("Empty transactions array"); - } - - return $res->getResponse()->transactions[0]; - } else { - throw new Exception('Invalid payment id'); + if (count($res->getResponse()->transactions) == 0) { + throw new Exception("Empty transactions array"); } - } catch (Exception $e) { - $this->log('PAYU_TRANSACTION_ERR', $e->getMessage(), $order->order_id()); - return $e->getMessage(); + + return $res->getResponse()->transactions[0]; + } else { + throw new Exception('Invalid payment id'); } } function payments($lang = 'pl') + { + $res = OpenPayU_Retrieve::payMethods($lang); + return $res->getResponse(); + } + + /** + * Get notifications from payu + * + * @return Response Return http response with status 200 or 422. + */ + function notify() { try { - $res = OpenPayU_Retrieve::payMethods($lang); + if (!in_array($this->ipAddress(), $this->allowed_ip)) { + throw new Exception('Notify invalid ip address', 422); + } + + $data = trim(request()->getContent()); // Json - return $res->getResponse(); + if (empty($data)) { + throw new Exception('Notify invalid data'); + } + + if ($this->env == 'sandbox') { + Log::info($data, [ + 'error' => 'PAYU_NOTIFY', + 'ip' => $this->ipAddress() + ]); + } + + // Prepare notification + $notify = OpenPayU_Order::consumeNotification($data); + + if (!$notify instanceof OpenPayU_Result) { + throw new Exception("Notify invalid object"); + } + + PayuPaymentNotified::dispatch($notify); + + // Confirm Order + if (!empty($notify->getResponse()->order->extOrderId)) { + $p = Payment::where('id', $notify->getResponse()->order->extOrderId)->first(); + if ($p instanceof Payment) { + $this->refresh(Order::find($p->order_id)); + return response("Comfirmed", 200); + } + } + + // Confirm Refund + if ( + !empty($notify->getResponse()->refund) && + !empty($notify->getResponse()->extOrderId) + ) { + $p = Payment::where('id', $notify->getResponse()->extOrderId)->first(); + if ($p instanceof Payment) { + $this->refunds(Order::find($p->order_id)); + return response("Comfirmed", 200); + } + } + + throw new Exception("Invalid notification content"); } catch (Exception $e) { - $this->log('PAYU_PAYMENTS_ERR', $e->getMessage()); - return $e->getMessage(); + Log::info($e->getMessage(), [ + 'error' => 'PAYU_NOTIFIY', + 'ip' => $this->ipAddress() + ]); + return response("Not comfirmed", 422); } } @@ -484,7 +439,7 @@ function notifyUrl(): string function successUrl(PayuOrderInterface $order): string { // https://your.page/web/payment/success/{order} - return request()->getSchemeAndHttpHost() . '/web/payment/success/payu/' . $order->order_id() . '?lang=' . app()->getLocale(); + return request()->getSchemeAndHttpHost() . '/web/payment/success/payu/' . $order->orderId() . '?lang=' . app()->getLocale(); } function ipAddress(): string @@ -516,23 +471,6 @@ function toCents(float $decimal): int throw new Exception("Invalid decimal value", 422); } - return number_format($decimal * 100, 2, '.', ''); - } - - function log($code, $desc, $oid = 'NONE') - { - try { - if (config('payu.logs.errors', true) == true) { - PayuLog::create([ - 'code' => $code, - 'description' => $desc, - 'oid' => $oid, - 'ip' => $this->ipAddress(), - ]); - } - } catch (Exception $e) { - report($e); - throw new Exception("PayuLog log error", 422); - } + return number_format($decimal * 100, 0, '.', ''); } } diff --git a/src/Http/Controllers/PayuPaymentController.php b/src/Http/Controllers/PayuPaymentController.php index 749d0bb..f9e3e4d 100644 --- a/src/Http/Controllers/PayuPaymentController.php +++ b/src/Http/Controllers/PayuPaymentController.php @@ -5,7 +5,11 @@ use App\Http\Controllers\Controller; use App\Models\Order; use Payu\Facades\Payu; +use Illuminate\Database\QueryException; +use PDOException; +use Exception; +// Sandbox testing only class PayuPaymentController extends Controller { function notify() @@ -13,66 +17,163 @@ function notify() return Payu::notify(); } + function create() + { + try { + $order = Order::create([ + 'cost' => 123.79, + 'firstname' => 'Marysia', + 'lastname' => 'Malinka', + 'email' => 'masysia@localhost', + 'phone' => '+48100200300', + 'payment_method' => 'online', + 'payment_gateway' => 'payu', + ]); + + $url = Payu::pay($order); + + return response()->json([ + 'url' => $url, + 'order_id' => $order->id + ]); + } catch (Exception $e) { + report($e); + return response($e->getMessage(), 422); + } + } + function pay(Order $order) { - return response()->json([ - 'url' => Payu::pay($order) - ]); + try { + return response()->json([ + 'url' => Payu::pay($order) + ]); + } catch (PDOException | QueryException $e) { + report($e); + return response('Database error', 422); + } catch (Exception $e) { + report($e); + return response($e->getMessage(), 422); + } } function confirm(Order $order) { - return response()->json([ - 'message' => Payu::confirm($order) - ]); + try { + return response()->json([ + 'message' => Payu::confirm($order) + ]); + } catch (PDOException | QueryException $e) { + report($e); + return response('Database error', 422); + } catch (Exception $e) { + report($e); + return response($e->getMessage(), 422); + } } function cancel(Order $order) { - return response()->json([ - 'message' => Payu::cancel($order) - ]); + try { + return response()->json([ + 'message' => Payu::cancel($order) + ]); + } catch (PDOException | QueryException $e) { + report($e); + return response('Database error', 422); + } catch (Exception $e) { + report($e); + return response($e->getMessage(), 422); + } } function refresh(Order $order) { - return response()->json([ - 'message' => Payu::refresh($order) - ]); + try { + return response()->json([ + 'message' => Payu::refresh($order) + ]); + } catch (PDOException | QueryException $e) { + report($e); + return response('Database error', 422); + } catch (Exception $e) { + report($e); + return response($e->getMessage(), 422); + } } function retrive(Order $order) { - return response()->json([ - 'message' => Payu::retrive($order) - ]); + try { + return response()->json([ + 'message' => Payu::retrive($order) + ]); + } catch (PDOException | QueryException $e) { + report($e); + return response('Database error', 422); + } catch (Exception $e) { + report($e); + return response($e->getMessage(), 422); + } } function transaction(Order $order) { - return response()->json([ - 'message' => Payu::transaction($order) - ]); + try { + return response()->json([ + 'message' => Payu::transaction($order) + ]); + } catch (PDOException | QueryException $e) { + report($e); + return response('Database error', 422); + } catch (Exception $e) { + report($e); + return response($e->getMessage(), 422); + } } function refund(Order $order) { - return response()->json([ - 'message' => Payu::refund($order) - ]); + try { + return response()->json([ + 'message' => Payu::refund($order) + ]); + } catch (PDOException | QueryException $e) { + report($e); + return response('Database Error.', 422); + } catch (Exception $e) { + report($e); + return response($e->getMessage(), 422); + } } function refunds(Order $order) { - return response()->json([ - 'message' => Payu::refunds($order) - ]); + try { + return response()->json([ + 'message' => Payu::refunds($order) + ]); + } catch (PDOException | QueryException $e) { + report($e); + return response('Database error', 422); + } catch (Exception $e) { + report($e); + return response($e->getMessage(), 422); + } } function payments($lang) { - return response()->json([ - 'message' => Payu::payments($lang) - ]); + try { + return response()->json([ + 'message' => Payu::payments($lang) + ]); + } catch (PDOException | QueryException $e) { + report($e); + return response('Database error', 422); + } catch (Exception $e) { + report($e); + return response($e->getMessage(), 422); + } } } diff --git a/src/Http/Payu/OpenPayU_Refunds.php b/src/Http/Payu/OpenPayU_Refunds.php index 7e65bb7..9e422bf 100644 --- a/src/Http/Payu/OpenPayU_Refunds.php +++ b/src/Http/Payu/OpenPayU_Refunds.php @@ -18,12 +18,10 @@ public static function retrive($orderId) try { $authType = self::getAuth(); + $pathUrl = OpenPayU_Configuration::getServiceUrl() . 'orders/' . $orderId . '/refunds'; + return self::verifyResponse(OpenPayU_Http::doGet($pathUrl, $authType)); } catch (OpenPayU_Exception $e) { throw new OpenPayU_Exception($e->getMessage(), $e->getCode()); } - - $pathUrl = OpenPayU_Configuration::getServiceUrl() . 'orders/' . $orderId . '/refunds'; - - return self::verifyResponse(OpenPayU_Http::doGet($pathUrl, $authType)); } } diff --git a/src/Interfaces/PayuOrderInterface.php b/src/Interfaces/PayuOrderInterface.php index c3f2df6..d9ac18e 100644 --- a/src/Interfaces/PayuOrderInterface.php +++ b/src/Interfaces/PayuOrderInterface.php @@ -4,10 +4,10 @@ interface PayuOrderInterface { - function order_id(); - function order_cost(); - function order_firstname(); - function order_lastname(); - function order_phone(); - function order_email(); + function orderId(); + function orderCost(); + function orderFirstname(); + function orderLastname(); + function orderPhone(); + function orderEmail(); } diff --git a/src/Listeners/PayuPaymentNotification.php b/src/Listeners/PayuPaymentNotification.php new file mode 100644 index 0000000..07f77a4 --- /dev/null +++ b/src/Listeners/PayuPaymentNotification.php @@ -0,0 +1,13 @@ + $event]); + } +} diff --git a/src/Models/PayuLog.php b/src/Models/PayuLog.php deleted file mode 100644 index 592f11e..0000000 --- a/src/Models/PayuLog.php +++ /dev/null @@ -1,32 +0,0 @@ -format($this->dateFormat); - } - - public static function getRandomRow() - { - return self::inRandomOrder()->first(); - } -} diff --git a/src/Payu.php b/src/Payu.php index 4420e4f..68a3f74 100644 --- a/src/Payu.php +++ b/src/Payu.php @@ -2,6 +2,7 @@ namespace Payu; +use Exception; use Payu\Gateways\PayuPaymentGateway; use Payu\Interfaces\PayuOrderInterface; diff --git a/src/PayuServiceProvider.php b/src/PayuServiceProvider.php index 685b672..1ab42d8 100644 --- a/src/PayuServiceProvider.php +++ b/src/PayuServiceProvider.php @@ -5,6 +5,7 @@ use Illuminate\Support\ServiceProvider; use Payu\Gateways\PayuPaymentGateway; use Payu\Http\Middleware\PayuMiddleware; +use Payu\Providers\PayuEventServiceProvider; use Payu\Payu; class PayuServiceProvider extends ServiceProvider @@ -16,24 +17,26 @@ class PayuServiceProvider extends ServiceProvider */ public function register() { - $this->app['router']->aliasMiddleware('payu', PayuMiddleware::class); - $this->mergeConfigFrom(__DIR__ . '/../config/config.php', 'payu'); - // Facade - $this->app->bind('payu', function ($app) { - return new Payu(); - }); - // Enable payu gateway if (config('payu.enable') == true) { + // Middleware + $this->app['router']->aliasMiddleware('payu', PayuMiddleware::class); + // Facade + $this->app->bind('payu', function ($app) { + return new Payu(); + }); + // Service $this->app->bind(PayuPaymentGateway::class, function ($app) { return new PayuPaymentGateway(); }); + // Events + if (config('payu.env') == 'sandbox') { + // Event service + $this->app->register(PayuEventServiceProvider::class); + } } - - // Event service - // $this->app->register(PayuEventServiceProvider::class); } /** diff --git a/src/Providers/PayuEventServiceProvider.php b/src/Providers/PayuEventServiceProvider.php new file mode 100644 index 0000000..aae767e --- /dev/null +++ b/src/Providers/PayuEventServiceProvider.php @@ -0,0 +1,42 @@ + [ + PayuPaymentNotification::class, + ], + PayuPaymentNotified::class => [ + PayuPaymentNotification::class, + ], + PayuPaymentRefunded::class => [ + PayuPaymentNotification::class, + ], + PayuPaymentCanceled::class => [ + PayuPaymentNotification::class, + ], + PayuPaymentConfirmed::class => [ + PayuPaymentNotification::class, + ] + ]; + + /** + * Register any events for your application. + * + * @return void + */ + public function boot() + { + parent::boot(); + } +} diff --git a/tests/Payu/PayuTest.php b/tests/Payu/PayuTest.php index ee15ed8..014db92 100644 --- a/tests/Payu/PayuTest.php +++ b/tests/Payu/PayuTest.php @@ -161,8 +161,8 @@ public function notify_success_pages() $res->assertStatus(422); $o = Order::create([ - 'firstname' => 'Kill', - 'lastname' => 'Bill', + 'firstname' => 'Mary', + 'lastname' => 'Jane', 'phone' => '+48000000000', 'email' => 'user@localhost', 'payment_method' => 'online', diff --git a/tests/README.md b/tests/README.md index 86cb602..74b0bf9 100644 --- a/tests/README.md +++ b/tests/README.md @@ -1,6 +1,79 @@ -# Testing, dev +# Test -### Update migrations +## Database and user + +mysql -u root + +```sql +CREATE DATABASE IF NOT EXISTS laravel_testing CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +GRANT ALL PRIVILEGES ON laravel_testing.* TO testing@localhost IDENTIFIED BY 'toor' WITH GRANT OPTION; +GRANT ALL PRIVILEGES ON laravel_testing.* TO testing@127.0.0.1 IDENTIFIED BY 'toor' WITH GRANT OPTION; +FLUSH PRIVILEGES; + +# Clear or change password +SET PASSWORD FOR root@localhost=PASSWORD(''); + +# Change password +ALTER USER 'testing'@'localhost' IDENTIFIED BY 'toor'; +FLUSH PRIVILEGES; +``` + +### Config .env.testing + +```php +DB_CONNECTION=mysql +DB_HOST=127.0.0.1 +DB_PORT=3306 +DB_DATABASE=laravel_testing +DB_USERNAME=testing +DB_PASSWORD=toor +``` + +### Migration, seed + +```sh +# Migracja i populacja tabel +php artisan --env=testing migrate +php artisan --env=testing migrate:fresh + +# Tylko populacja tabel (przykład) +php artisan --env=testing db:seed --class="\Database\Seeders\PayuDatabaseSeeder" + +# Lub dodaj w katalogu databases/seeders/DatabaseSeeder.php aplikacji (przykład) +$this->call([ + PayuDatabaseSeeder::class, +]); +``` + +### Settings phpunit.xml + +```xml + + ./vendor/atomjoy/payu/tests/Payu + + + + + +``` + +### Dirs + +```sh +sudo chown -R www-data:www-data storage/framework/cache +sudo chmod -R 770 storage/framework/cache +``` + +### Run tests + +```sh +# Tests only for config(['payu.env' => 'sandbox']) +php artisan test --testsuite=Payu --stop-on-failure +``` + +## Table update (examples) + +### Make migration ```sh php artisan make:migration UpdatePayuTables @@ -17,44 +90,44 @@ use Illuminate\Support\Facades\Schema; class UpdatePayuTables extends Migration { - public function up() - { - Schema::table('orders', function (Blueprint $table) { - // Columns - if (!Schema::hasColumn('orders', 'user_id')) { - $table->unsignedBigInteger('user_id')->nullable(true)->after('uid'); - } - - // Indexes - $table->index('user_id'); - $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade')->onUpdate('cascade'); - }); - - Schema::table('clients', function (Blueprint $table) { - $table->string('zip', 10)->nullable(true)->after('country'); - }); - } - - public function down() - { - Schema::table('orders', function (Blueprint $table) { - // Indexes - $table->dropForeign('orders_user_id_foreign'); - $table->dropIndex('orders_user_id_index'); - - // Drop columns - $table->dropColumn([ - 'user_id' - ]); - }); - - Schema::table('clients', function (Blueprint $table) { - // Drop columns - $table->dropColumn([ - 'zip' - ]); - }); - } + public function up() + { + Schema::table('orders', function (Blueprint $table) { + // Columns + if (!Schema::hasColumn('orders', 'user_id')) { + $table->unsignedBigInteger('user_id')->nullable(true)->after('uid'); + } + + // Indexes + $table->index('user_id'); + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade')->onUpdate('cascade'); + }); + + Schema::table('clients', function (Blueprint $table) { + $table->string('zip', 10)->nullable(true)->after('country'); + }); + } + + public function down() + { + Schema::table('orders', function (Blueprint $table) { + // Indexes + $table->dropForeign('orders_user_id_foreign'); + $table->dropIndex('orders_user_id_index'); + + // Drop columns + $table->dropColumn([ + 'user_id' + ]); + }); + + Schema::table('clients', function (Blueprint $table) { + // Drop columns + $table->dropColumn([ + 'zip' + ]); + }); + } } ``` @@ -62,6 +135,7 @@ class UpdatePayuTables extends Migration ```sh php artisan migrate +php artisan migrate:fresh ``` ### Update model sample @@ -114,102 +188,21 @@ php artisan session:table php artisan queue:table ``` -## Tests - -### Database and user - -mysql -u root - -```sql -# Create database -CREATE DATABASE IF NOT EXISTS laravel_testing CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - -# Privileges and user with pass -GRANT ALL PRIVILEGES ON laravel_testing.* TO testing@localhost IDENTIFIED BY 'toor' WITH GRANT OPTION; -GRANT ALL PRIVILEGES ON laravel_testing.* TO testing@127.0.0.1 IDENTIFIED BY 'toor' WITH GRANT OPTION; -FLUSH PRIVILEGES; - -# Change password -ALTER USER 'testing'@'localhost' IDENTIFIED BY 'toor'; -FLUSH PRIVILEGES; -``` - -### Config .env.testing - -```php -DB_CONNECTION=mysql -DB_HOST=127.0.0.1 -DB_PORT=3306 -DB_DATABASE=laravel_testing -DB_USERNAME=testing -DB_PASSWORD=toor -``` - -### Migration, seed - -```sh -# Migracja i populacja tabel -php artisan --env=testing migrate:fresh -# Tylko populacja tabel -php artisan --env=testing db:seed --class="\Database\Seeders\PayuDatabaseSeeder" - -# Lub dodaj w katalogu databases/seeders/DatabaseSeeder.php aplikacji -$this->call([ - PayuDatabaseSeeder::class, -]); - -# migracje i seeders -php artisan --env=testing migrate:fresh --seed -``` - -### Settings phpunit.xml - -```xml - - ./vendor/atomjoy/payu/tests/Payu - - - - - -``` - -### Dirs - -```sh -sudo chown -R www-data:www-data storage/framework/cache -sudo chmod -R 770 storage/framework/cache -``` - -### Run tests - -```sh -# Tests only for config(['payu.env' => 'sandbox']) -php artisan test --testsuite=Payu --stop-on-failure -``` - -### Copy tests - -```sh -# Copy package test/Pay dir -php artisan vendor:publish --tag=payu-tests --force -``` - ## Composer ### Local directory ```json { - "repositories": [ - { - "type": "path", - "url": "packages/atomjoy/payu" - } - ], - "require": { - "atomjoy/payu": "dev-main" - } + "repositories": [ + { + "type": "path", + "url": "packages/atomjoy/payu" + } + ], + "require": { + "atomjoy/payu": "dev-main" + } } ``` @@ -217,15 +210,15 @@ php artisan vendor:publish --tag=payu-tests --force ```json { - "repositories": [ - { - "type": "vcs", - "url": "https://github.com/atomjoy/payu" - } - ], - "require": { - "atomjoy/payu": "*" - } + "repositories": [ + { + "type": "vcs", + "url": "https://github.com/atomjoy/payu" + } + ], + "require": { + "atomjoy/payu": "*" + } } ``` @@ -237,12 +230,12 @@ composer require atomjoy/payu "~1.0.0" # composer.json { - "require": { - "atomjoy/payu": "~1.0.0" - } + "require": { + "atomjoy/payu": "~1.0.0" + } } ``` ## Payment APIs -https://github.com/PayU-EMEA/openpayu_php +