laravel-netopia maintained by gabrieldevro
Ce face
| 🔗 Pornire plată | Netopia::startPayment() trimite comanda și întoarce URL-ul paginii de plată NETOPIA |
| 🔎 Status | Netopia::status() interoghează tranzacția, util ca verificare suplimentară |
| 🔐 IPN securizat | verifică JWT-ul Verification-token (RS512) cu cheia publică NETOPIA, emitentul, POS-ul, expirarea și hash-ul SHA-512 al corpului |
| 📣 Evenimente | fiecare IPN valid emite NetopiaPaymentUpdated, pe care îl asculți ca să marchezi comanda |
| 🧪 Sandbox | trecerea între test și producție se face dintr-o singură variabilă |
Fără SDK extern: doar HTTP client-ul Laravel și OpenSSL.
Instalare
composer require gabrieldevro/laravel-netopia
php artisan vendor:publish --tag=netopia-config # opțional
.env:
NETOPIA_API_KEY=cheia-din-panoul-netopia
NETOPIA_POS_SIGNATURE=XXXX-XXXX-XXXX-XXXX-XXXX
NETOPIA_SANDBOX=true
NETOPIA_PUBLIC_KEY=/cale/catre/netopia-public.cer # sau conținutul PEM
NETOPIA_NOTIFY_URL="${APP_URL}/netopia/ipn"
NETOPIA_REDIRECT_URL="${APP_URL}/comanda/finalizata"
Utilizare
1. Pornești plata
use Gabrieldev\Netopia\Facades\Netopia;
$result = Netopia::startPayment([
'orderID' => $order->number,
'amount' => $order->total, // 249.90 (lei, nu bani)
'description' => "Comanda #{$order->number}",
'billing' => [
'email' => $order->email, 'phone' => $order->phone,
'firstName' => $order->first_name, 'lastName' => $order->last_name,
'city' => $order->city, 'details' => $order->address,
],
'products' => $order->items->map(fn ($i) => [
'name' => $i->name, 'code' => $i->sku, 'category' => 'produse', 'price' => $i->price, 'vat' => 19,
])->all(),
]);
$order->update(['ntp_id' => $result->ntpId]);
return redirect()->away($result->paymentUrl);
2. Primești confirmarea (IPN)
Pachetul înregistrează automat POST /netopia/ipn. Ruta trebuie exclusă de la verificarea CSRF, pentru că NETOPIA nu trimite token:
// bootstrap/app.php
->withMiddleware(fn ($m) => $m->validateCsrfTokens(except: ['netopia/ipn']))
Asculți evenimentul:
use Gabrieldev\Netopia\Events\NetopiaPaymentUpdated;
Event::listen(function (NetopiaPaymentUpdated $event) {
$order = Order::where('number', $event->orderId)->firstOrFail();
match (true) {
$event->status->isSuccessful() => $order->markAsPaid($event->ntpId),
$event->status->isFailed() => $order->markAsFailed($event->status->name),
default => null, // în așteptare
};
});
Un IPN cu semnătură greșită, corp modificat, alt POS sau token expirat primește 400 și nu emite evenimentul.
Statusuri
PaymentStatus este un enum cu toate statusurile API v2 (Paid, Confirmed, Pending, Declined, Canceled, Expired etc.) și metodele isSuccessful(), isFailed() și isPending().
Teste
composer test
Testele rulează offline:
- HTTP-ul către NETOPIA e simulat cu
Http::fake(). - IPN-ul e semnat cu o pereche de chei RSA generată la rulare.
- Cazurile acoperite: corp modificat, alt POS, alt emitent, token expirat, header lipsă și semnătură cu altă cheie.
Notă. Pachetul folosește API-ul v2 NETOPIA, cu endpoint-urile
/payment/card/startși/operation/status. Testează întotdeauna în sandbox și verifică formatul exact al câmpurilor cu documentația oficială NETOPIA pentru contul tău înainte de a trece în producție.