Skip to content
Merged
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
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,23 @@ For example create a POST route in routes folder, web.php like this:
Route::post('payment/callback', 'YourController@handleCallback')->name('payment.callback');
```

`NOTE: SOME GATEWAYS MAY USE GET METHOD FOR CALLBACK (like Zarinpal)`

then set the route name in .env file:

```ini
LARAPAY_PAYMENT_CALLBACK=payment.callback
```

remember to add callback route to except array of validateCsrfToken

add this in `withMiddleware` section in `bootstrap/app.php` :
```php
$middleware->validateCsrfTokens(except: [
'payment/*',
]);
```


## Usage

Expand Down
2 changes: 1 addition & 1 deletion config/larapay.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
| the gateways list is comma separated
|
*/
'gateways' => env('LARAPAY_GATES', 'Mellat,Saman,Pasargad,Parsian,ZarinPal,Idpay,Payir,Saderat,Zibal,Nextpay'),
'gateways' => env('LARAPAY_GATES', 'Mellat,Saman,Pasargad,Parsian,Zarinpal,Idpay,Payir,Saderat,Zibal,Nextpay'),

/*
|--------------------------------------------------------------------------
Expand Down
24 changes: 24 additions & 0 deletions src/Adapter/AdapterAbstract.php
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,30 @@ protected function getEndPoint(): string
}
}

/**
* @return string
*/
protected function getPaymentRequestEndpPoint():string
{
if (config('larapay.mode') === 'production') {
return $this->paymentRequestEndPoint;
} else {
return $this->testPaymentRequestEndPoint;
}
}

/**
* @return string
*/
protected function getPaymentVerifyEndpPoint():string
{
if (config('larapay.mode') === 'production') {
return $this->paymentVerifyEndPoint;
} else {
return $this->testPaymentVerifyEndPoint;
}
}

/**
* @param array $options
*
Expand Down
109 changes: 51 additions & 58 deletions src/Adapter/Zarinpal.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

use SoapClient;
use SoapFault;
use PhpMonsters\Larapay\Adapter\Zarinpal\Helper;
use PhpMonsters\Larapay\Adapter\Zarinpal\Exception;
use PhpMonsters\Log\Facades\XLog;

Expand All @@ -14,14 +15,18 @@
*/
class Zarinpal extends AdapterAbstract implements AdapterInterface
{
protected $WSDL = 'https://www.zarinpal.com/pg/services/WebGate/wsdl';
protected $paymentRequestEndPoint = "https://payment.zarinpal.com/pg/v4/payment/request.json";
protected $paymentVerifyEndPoint = "https://payment.zarinpal.com/pg/v4/payment/verify.json";

protected $endPoint = 'https://www.zarinpal.com/pg/StartPay/{authority}';
protected $zarinEndPoint = 'https://www.zarinpal.com/pg/StartPay/{authority}/ZarinGate';

protected $endPoint = 'https://www.zarinpal.com/pg/StartPay/{authority}';
protected $zarinEndPoint = 'https://www.zarinpal.com/pg/StartPay/{authority}/ZarinGate';
protected $mobileEndPoint = 'https://www.zarinpal.com/pg/StartPay/{authority}/MobileGate';

protected $testWSDL = 'https://banktest.ir/gateway/zarinpal/ws?wsdl';
protected $testEndPoint = 'https://banktest.ir/gateway/zarinpal/gate/{authority}';
protected $testEndPoint = 'https://sandbox.banktest.ir/zarinpal/www.zarinpal.com/pg/StartPay/{authority}';
protected $testPaymentRequestEndPoint = "https://sandbox.banktest.ir/zarinpal/api.zarinpal.com/pg/v4/payment/request.json";
protected $testPaymentVerifyEndPoint = "https://sandbox.banktest.ir/zarinpal/api.zarinpal.com/pg/v4/payment/verify.json";


public $reverseSupport = false;

Expand All @@ -43,42 +48,39 @@ protected function requestToken(): string
]);

$sendParams = [
'MerchantID' => $this->merchant_id,
'Amount' => intval($this->amount),
'Description' => $this->description ? $this->description : '',
'Email' => $this->email ? $this->email : '',
'Mobile' => $this->mobile ? $this->mobile : '',
'CallbackURL' => $this->redirect_url,
'merchant_id' => $this->merchant_id,
'amount' => intval($this->amount),
'description' => $this->description ? $this->description : '',
"metadata" => [
'mobile' => $this->mobile ? $this->mobile : '',
'email' => $this->email ? $this->email : '',
],
'callback_url' => $this->redirect_url,
];

try {
$soapClient = new SoapClient($this->getWSDL());

XLog::debug('PaymentRequest call', $sendParams);

$response = $soapClient->PaymentRequest($sendParams);

XLog::info('PaymentRequest response', $this->obj2array($response));

$response = Helper::post2https($sendParams, $this->getPaymentRequestEndpPoint());
$result = json_decode($response);
XLog::info('reservation result', $result);

if (isset($response->Status)) {
if (empty($result->errors)) {
if ($result->data->code == 100) {
$this->getTransaction()->setGatewayToken(strval($result->data->authority)); // update transaction reference id

if ($response->Status == 100) {
$this->getTransaction()->setGatewayToken(strval($response->Authority)); // update transaction reference id

return $response->Authority;
return $result->data->authority;
} else {
throw new Exception($response->Status);
throw new Exception('no error provided and not 100');
}
} else {
throw new Exception('larapay::larapay.invalid_response');
throw new Exception('code: ' . $result->errors->code . "\n" . 'message: ' . $result->errors->message);
}
} catch (SoapFault $e) {
throw new Exception('SoapFault: ' . $e->getMessage() . ' #' . $e->getCode(), $e->getCode());
} catch (\Exception $e) {
throw new Exception($e->getMessage());
}
}


/**
* @return string
* @throws Exception
Expand All @@ -89,9 +91,9 @@ protected function generateForm(): string
$authority = $this->requestToken();

$form = view('larapay::zarinpal-form', [
'endPoint' => strtr($this->getEndPoint(), ['{authority}' => $authority]),
'endPoint' => strtr($this->getEndPoint(), ['{authority}' => $authority]),
'submitLabel' => !empty($this->submit_label) ? $this->submit_label : trans("larapay::larapay.goto_gate"),
'autoSubmit' => boolval($this->auto_submit),
'autoSubmit' => boolval($this->auto_submit),
]);

return $form->__toString();
Expand All @@ -106,8 +108,8 @@ public function formParams(): array
{
$authority = $this->requestToken();

return [
'endPoint' => strtr($this->getEndPoint(), ['{authority}' => $authority]),
return [
'endPoint' => strtr($this->getEndPoint(), ['{authority}' => $authority]),
];
}

Expand All @@ -128,38 +130,29 @@ protected function verifyTransaction(): bool
]);

$sendParams = [
'MerchantID' => $this->merchant_id,
'Authority' => $this->Authority,
'Amount' => intval($this->transaction->amount),
'merchant_id' => $this->merchant_id,
'authority' => $this->Authority,
'amount' => intval($this->transaction->amount),
];

try {
$soapClient = new SoapClient($this->getWSDL());

XLog::debug('PaymentVerification call', $sendParams);

$response = $soapClient->PaymentVerification($sendParams);
XLog::debug('PaymentVerification call', $sendParams);

XLog::info('PaymentVerification response', $this->obj2array($response));


if (isset($response->Status, $response->RefID)) {

if ($response->Status == 100) {
$this->getTransaction()->setVerified();
$this->getTransaction()->setReferenceId((string)$response->RefID); // update transaction reference id

return true;
} else {
throw new Exception($response->Status);
}
try {
$response = Helper::post2https($sendParams, $this->getPaymentVerifyEndpPoint());
$result = json_decode($response);
XLog::info('PaymentVerification response', $this->obj2array($result));

if ($result->data->code === 100) {
$this->getTransaction()->setVerified();
$this->getTransaction()->setReferenceId((string) $result->data->ref_id); // update transaction reference id
return true;
} else if ($result->data->code === 101) {
return true;
} else {
throw new Exception('larapay::larapay.invalid_response');
throw new Exception('code: ' . $result->errors->code . "\n" . 'message: ' . $result->errors->message);
}

} catch (SoapFault $e) {

throw new Exception('SoapFault: ' . $e->getMessage() . ' #' . $e->getCode(), $e->getCode());
} catch (\Exception $e) {
throw new Exception("Payment Verify Error: " . $e->getMessage());
}
}

Expand Down
47 changes: 47 additions & 0 deletions src/Adapter/Zarinpal/Helper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php
namespace PhpMonsters\Larapay\Adapter\Zarinpal;

use PhpMonsters\Log\Facades\XLog;

class Helper
{
/**
* CURL POST TO HTTPS
*
* @param $fields_arr
* @param $url
* @return mixed
*/
public static function post2https($fields_arr, $url)
{
$header = [
'Content-Type: application/json',
];

$ch = curl_init();
//set the url, number of POST vars, POST data
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_USERAGENT, 'ZarinPal Rest Api v4');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields_arr));
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);

//execute post
$res = curl_exec($ch);

// error
$err = curl_error($ch);

//close connection
curl_close($ch);

if ($err) {
throw new Exception("cURL Error #:$err");
}

XLog::debug('Zarinpal call response: ' . $res);
return $res;
}
}