Skip to content

Commit

Permalink
Feature/rafactor pasargad (#78)
Browse files Browse the repository at this point in the history
* refactor: make rsa class methods static

* refactor: Pasargad driver

* refactor: make RSA class PSR-2 compatible

* refactor: Pasargad driver according to new rest Api
  • Loading branch information
na3r authored Jun 7, 2020
1 parent 7f24b08 commit bc42c3f
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 167 deletions.
7 changes: 4 additions & 3 deletions config/payment.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,10 @@
'description' => 'payment in '.config('app.name'),
],
'pasargad' => [
'apiPaymentUrl' => 'https://pep.shaparak.ir/gateway.aspx',
'apiCheckTransactionUrl' => 'https://pep.shaparak.ir/CheckTransactionResult.aspx',
'apiVerificationUrl' => 'https://pep.shaparak.ir/VerifyPayment.aspx',
'apiPaymentUrl' => 'https://pep.shaparak.ir/payment.aspx',
'apiGetToken' => 'https://pep.shaparak.ir/Api/v1/Payment/GetToken',
'apiCheckTransactionUrl' => 'https://pep.shaparak.ir/Api/v1/Payment/CheckTransactionResult',
'apiVerificationUrl' => 'https://pep.shaparak.ir/Api/v1/Payment/VerifyPayment',
'merchantId' => '',
'terminalCode' => '',
'certificate' => '', // can be string (and set certificateType to xml_string) or an xml file path (and set cetificateType to xml_file)
Expand Down
193 changes: 89 additions & 104 deletions src/Drivers/Pasargad/Pasargad.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,23 @@

namespace Shetabit\Payment\Drivers\Pasargad;

use GuzzleHttp\Client;
use Shetabit\Payment\Invoice;
use Shetabit\Payment\Receipt;
use Shetabit\Payment\Abstracts\Driver;
use Shetabit\Payment\Exceptions\InvalidPaymentException;
use Shetabit\Payment\Exceptions\PurchaseFailedException;
use Shetabit\Payment\Contracts\ReceiptInterface;
use Shetabit\Payment\Exceptions\InvalidPaymentException;
use Shetabit\Payment\Drivers\Pasargad\Utils\RSAProcessor;
use Shetabit\Payment\Invoice;
use Shetabit\Payment\Receipt;

class Pasargad extends Driver
{
/**
* Guzzle client
*
* @var object
*/
protected $client;

/**
* Invoice
*
Expand Down Expand Up @@ -44,6 +51,7 @@ public function __construct(Invoice $invoice, $settings)
{
$this->invoice($invoice);
$this->settings = (object) $settings;
$this->client = new Client();
}

/**
Expand All @@ -55,7 +63,7 @@ public function purchase()
{
$invoiceData = $this->getPreparedInvoiceData();

$this->invoice->transactionId($invoiceData['signed']);
$this->invoice->transactionId($invoiceData['InvoiceNumber']);

// return the transaction's id
return $this->invoice->getTransactionId();
Expand All @@ -69,10 +77,11 @@ public function purchase()
public function pay()
{
$paymentUrl = $this->settings->apiPaymentUrl;
$data = array_merge($this->getPreparedInvoiceData(), ['submit' => 'Checkout']);
$getTokenUrl = $this->settings->apiGetToken;
$tokenData = $this->request($getTokenUrl, $this->getPreparedInvoiceData());

// redirect using HTML form
return $this->redirectWithForm($paymentUrl, $data, 'POST');
return $this->redirectWithForm($paymentUrl, $tokenData, 'POST');
}

/**
Expand All @@ -85,55 +94,25 @@ public function pay()
*/
public function verify() : ReceiptInterface
{
$client = new Client();

$response = $client
->request(
'POST',
$this->settings->apiCheckTransactionUrl,
[
"form_params" => ['invoiceUID' => request()->input('tref')],
"http_errors" => false,
]
);

$invoiceDetails = $this->makeXMLTree($response->getBody()->getContents());
$referenceId = $invoiceDetails['resultObj']['transactionReferenceID'];
$traceNumber = $invoiceDetails['resultObj']['traceNumber'];
$referenceNumber = $invoiceDetails['resultObj']['referenceNumber'];

$invoiceData = $this->getPreparedInvoiceData();
$fields = array(
'InvoiceNumber' => request()->input('iN'),
'InvoiceDate' => request()->input('tref'),
'MerchantCode' => $invoiceData['merchantCode'],
'TerminalCode' => $invoiceData['terminalCode'],
'amount' => $invoiceData['amount'],
'TimeStamp' => $invoiceData['timeStamp'],
'sign' => $invoiceData['sign']
$invoiceDetails = $this->request(
$this->settings->apiCheckTransactionUrl,
[
'TransactionReferenceID' => request()->input('tref')
]
);

$fields = [
'MerchantCode' => $invoiceDetails['MerchantCode'],
'TerminalCode' => $invoiceDetails['TerminalCode'],
'InvoiceNumber' => $invoiceDetails['InvoiceNumber'],
'InvoiceDate' => $invoiceDetails['InvoiceDate'],
'Amount' => $invoiceDetails['Amount'],
'Timestamp' => date("Y/m/d H:i:s"),
];

$response = $client
->request(
'POST',
$this->settings->apiVerificationUrl,
[
"form_params" => $fields,
"http_errors" => false,
]
);
$verifyResult = $this->makeXMLTree($response->getBody()->getContents());

if (empty($verifyResult['actionResult']) || is_null($verifyResult['actionResult']['result'])) {
throw new InvalidPaymentException($this->getDefaultExceptionMessage());
}

if ($verifyResult['actionResult']['result'] === false) {
throw new InvalidPaymentException($verifyResult['actionResult']['resultMessage'] ?? $this->getDefaultExceptionMessage());
}
$verifyResult = $this->request($this->settings->apiVerificationUrl, $fields);

return $this->createReceipt($referenceId, $traceNumber, $referenceNumber);
return $this->createReceipt($verifyResult, $invoiceDetails);
}

/**
Expand All @@ -143,12 +122,18 @@ public function verify() : ReceiptInterface
*
* @return Receipt
*/
protected function createReceipt($referenceId, $traceNumber, $referenceNumber)
protected function createReceipt($verifyResult, $invoiceDetails)
{
$referenceId = $invoiceDetails['TransactionReferenceID'];
$traceNumber = $invoiceDetails['TraceNumber'];
$referenceNumber = $invoiceDetails['ReferenceNumber'];

$reciept = new Receipt('Pasargad', $referenceId);

$reciept->detail('trace_number', $traceNumber);
$reciept->detail('reference_number', $referenceNumber);
$reciept->detail('TraceNumber', $traceNumber);
$reciept->detail('ReferenceNumber', $referenceNumber);
$reciept->detail('MaskedCardNumber', $verifyResult['MaskedCardNumber']);
$reciept->detail('ShaparakRefNumber', $verifyResult['ShaparakRefNumber']);

return $reciept;
}
Expand Down Expand Up @@ -199,76 +184,76 @@ protected function getPreparedInvoiceData()
*
* @return array
*/
protected function prepareInvoiceData()
protected function prepareInvoiceData(): array
{
$action = "1003"; // 1003 : for buy request (bank standard)
$action = 1003; // 1003 : for buy request (bank standard)
$merchantCode = $this->settings->merchantId;
$terminalCode = $this->settings->terminalCode;
$amount = $this->invoice->getAmount() * 10; // convert to toman
$amount = $this->invoice->getAmount(); //rial
$redirectAddress = $this->settings->callbackUrl;
$invoiceNumber = crc32($this->invoice->getUuid()).rand(0, time());
$invoiceNumber = crc32($this->invoice->getUuid()) . rand(0, time());
$timeStamp = date("Y/m/d H:i:s");
$invoiceDate = date("Y/m/d H:i:s");

if (!empty($this->invoice->getDetails()['date'])) {
$invoiceDate = $this->invoice->getDetails()['date'];
} else {
$invoiceDate = date("Y/m/d H:i:s");
}

$data = "#". $merchantCode ."#". $terminalCode ."#". $invoiceNumber ."#". $invoiceDate ."#". $amount ."#". $redirectAddress ."#". $action ."#". $timeStamp ."#";
$data = sha1($data, true);
$data = $this->sign($data);
$signedData = base64_encode($data);

return [
'invoiceNumber' => $invoiceNumber,
'invoiceDate' => $invoiceDate,
'amount' => $amount,
'terminalCode' => $terminalCode,
'merchantCode' => $merchantCode,
'redirectAddress' => $redirectAddress,
'timeStamp' => $timeStamp,
'action' => $action,
'signed' => $signedData,
'InvoiceNumber' => $invoiceNumber,
'InvoiceDate' => $invoiceDate,
'Amount' => $amount,
'TerminalCode' => $terminalCode,
'MerchantCode' => $merchantCode,
'RedirectAddress' => $redirectAddress,
'Timestamp' => $timeStamp,
'Action' => $action,
];
}

/**
* Convert XML tree to array
* Prepare signature based on Pasargad document
*
* @param $data
* @param string $data
* @return string
*/
public function prepareSignature(string $data): string
{
return base64_encode($this->sign(sha1($data, true)));
}

/**
* Make request to pasargad's Api
*
* @param string $url
* @param array $body
* @param string $method
* @return array
*/
protected function makeXMLTree($data)
protected function request(string $url, array $body, $method = 'POST'): array
{
$ret = array();

$parser = xml_parser_create();
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
xml_parse_into_struct($parser, $data, $values, $tags);
xml_parser_free($parser);

$hash_stack = array();
foreach ($values as $key => $val) {
switch ($val['type']) {
case 'open':
array_push($hash_stack, $val['tag']);
break;
case 'close':
array_pop($hash_stack);
break;
case 'complete':
array_push($hash_stack, $val['tag']);
// uncomment to see what this function is doing
// echo("\$ret[" . implode($hash_stack, "][") . "] = '{$val[value]}';\n");
eval("\$ret[" . implode($hash_stack, "][") . "] = '{$val[value]}';");
array_pop($hash_stack);
break;
}
$body = json_encode($body);
$sign = $this->prepareSignature($body);

$response = $this->client->request(
'POST',
$url,
[
'body' => $body,
'headers' => [
'content-type' => 'application/json',
'Sign' => $sign
],
"http_errors" => false,
]
);

$result = json_decode($response->getBody(), true);

if ($result['IsSuccess'] === false) {
throw new InvalidPaymentException($result['Message']);
}

return $ret;
return $result;
}
}
Loading

0 comments on commit bc42c3f

Please sign in to comment.