src/Drivers/Saman/Saman.php
<?php
namespace Shetabit\Multipay\Drivers\Saman;
use Shetabit\Multipay\Abstracts\Driver;
use Shetabit\Multipay\Exceptions\InvalidPaymentException;
use Shetabit\Multipay\Exceptions\PurchaseFailedException;
use Shetabit\Multipay\Contracts\ReceiptInterface;
use Shetabit\Multipay\Invoice;
use Shetabit\Multipay\Receipt;
use Shetabit\Multipay\RedirectionForm;
use Shetabit\Multipay\Request;
class Saman extends Driver
{
/**
* Invoice
*
* @var Invoice
*/
protected $invoice;
/**
* Driver settings
*
* @var object
*/
protected $settings;
/**
* Saman constructor.
* Construct the class with the relevant settings.
*
* @param Invoice $invoice
* @param $settings
*/
public function __construct(Invoice $invoice, $settings)
{
$this->invoice($invoice);
$this->settings = (object)$settings;
}
/**
* Purchase Invoice.
*
* @return string
*
* @throws PurchaseFailedException
* @throws \SoapFault
*/
public function purchase()
{
$data = array(
'MID' => $this->settings->merchantId,
'ResNum' => $this->invoice->getUuid(),
'Amount' => $this->invoice->getAmount() * ($this->settings->currency == 'T' ? 10 : 1), // convert to rial
'CellNumber' => ''
);
//set CellNumber for get user cards
if (!empty($this->invoice->getDetails()['mobile'])) {
$data['CellNumber'] = $this->invoice->getDetails()['mobile'];
}
$soap = new \SoapClient(
$this->settings->apiPurchaseUrl,
[
'encoding' => 'UTF-8',
'cache_wsdl' => WSDL_CACHE_NONE,
'stream_context' => stream_context_create([
'ssl' => [
'ciphers' => 'DEFAULT:!DH',
],
]),
]
);
$response = $soap->RequestToken($data['MID'], $data['ResNum'], $data['Amount'], $data['CellNumber']);
$status = (int)$response;
if ($status < 0) { // if something has done in a wrong way
$this->purchaseFailed($response);
}
// set transaction id
$this->invoice->transactionId($response);
// return the transaction's id
return $this->invoice->getTransactionId();
}
/**
* Pay the Invoice
*
* @return RedirectionForm
*/
public function pay(): RedirectionForm
{
$payUrl = $this->settings->apiPaymentUrl;
return $this->redirectWithForm(
$payUrl,
[
'Token' => $this->invoice->getTransactionId(),
'RedirectUrl' => $this->settings->callbackUrl,
],
'POST'
);
}
/**
* Verify payment
*
* @return ReceiptInterface
*
* @throws InvalidPaymentException
* @throws \SoapFault
*/
public function verify(): ReceiptInterface
{
$data = array(
'RefNum' => Request::input('RefNum'),
'merchantId' => $this->settings->merchantId,
);
$soap = new \SoapClient(
$this->settings->apiVerificationUrl,
[
'encoding' => 'UTF-8',
'cache_wsdl' => WSDL_CACHE_NONE,
'stream_context' => stream_context_create([
'ssl' => [
'ciphers' => 'DEFAULT:!DH',
],
]),
]
);
$status = (int)$soap->VerifyTransaction($data['RefNum'], $data['merchantId']);
if ($status < 0) {
$this->notVerified($status);
}
$receipt = $this->createReceipt($data['RefNum']);
$receipt->detail([
'traceNo' => Request::input('TraceNo'),
'referenceNo' => Request::input('RRN'),
'transactionId' => Request::input('RefNum'),
'cardNo' => Request::input('SecurePan'),
]);
return $receipt;
}
/**
* Generate the payment's receipt
*
* @param $referenceId
*
* @return Receipt
*/
protected function createReceipt($referenceId)
{
$receipt = new Receipt('saman', $referenceId);
return $receipt;
}
/**
* Trigger an exception
*
* @param $status
*
* @throws PurchaseFailedException
*/
protected function purchaseFailed($status)
{
$translations = array(
-1 => ' تراکنش توسط خریدار کنسل شده است.',
-6 => 'سند قابل برگشت کامل یافته است. یا خارج از زمان 30 دقیقه ارسال شده است.',
-18 => 'IP Address فروشنده نامعتبر است.',
79 => 'مبلغ سند برگشتی، از مبلغ تراکنش اصلی بیشتر است.',
12 => 'درخواست برگشت یک تراکنش رسیده است، در حالی که تراکنش اصلی پیدا نمی شود.',
14 => 'شماره کارت نامعتبر است.',
15 => 'چنین صادر کننده کارتی وجود ندارد.',
33 => 'از تاریخ انقضای کارت گذشته است و کارت دیگر معتبر نیست.',
38 => 'رمز کارت 3 مرتبه اشتباه وارد شده است در نتیجه کارت غیر فعال خواهد شد.',
55 => 'خریدار رمز کارت را اشتباه وارد کرده است.',
61 => 'مبلغ بیش از سقف برداشت می باشد.',
93 => 'تراکنش Authorize شده است (شماره PIN و PAN درست هستند) ولی امکان سند خوردن وجود ندارد.',
68 => 'تراکنش در شبکه بانکی Timeout خورده است.',
34 => 'خریدار یا فیلد CVV2 و یا فیلد ExpDate را اشتباه وارد کرده است (یا اصلا وارد نکرده است).',
51 => 'موجودی حساب خریدار، کافی نیست.',
84 => 'سیستم بانک صادر کننده کارت خریدار، در وضعیت عملیاتی نیست.',
96 => 'کلیه خطاهای دیگر بانکی باعث ایجاد چنین خطایی می گردد.',
);
if (array_key_exists($status, $translations)) {
throw new PurchaseFailedException($translations[$status]);
} else {
throw new PurchaseFailedException('خطای ناشناخته ای رخ داده است.');
}
}
/**
* Trigger an exception
*
* @param $status
*
* @throws InvalidPaymentException
*/
private function notVerified($status)
{
$translations = array(
-1 => 'خطا در پردازش اطلاعات ارسالی (مشکل در یکی از ورودی ها و ناموفق بودن فراخوانی متد برگشت تراکنش)',
-3 => 'ورودی ها حاوی کارکترهای غیرمجاز میباشند.',
-4 => 'کلمه عبور یا کد فروشنده اشتباه است (Merchant Authentication Failed)',
-6 => 'سند قابل برگشت کامل یافته است. یا خارج از زمان 30 دقیقه ارسال شده است.',
-7 => 'رسید دیجیتالی تهی است.',
-8 => 'طول ورودی ها بیشتر از حد مجاز است.',
-9 => 'وجود کارکترهای غیرمجاز در مبلغ برگشتی.',
-10 => 'رسید دیجیتالی به صورت Base64 نیست (حاوی کاراکترهای غیرمجاز است)',
-11 => 'طول ورودی ها کمتر از حد مجاز است.',
-12 => 'مبلغ برگشتی منفی است.',
-13 => 'مبلغ برگشتی برای برگشت جزئی بیش از مبلغ برگشت نخورده ی رسید دیجیتالی است.',
-14 => 'چنین تراکنشی تعریف نشده است.',
-15 => 'مبلغ برگشتی به صورت اعشاری داده شده است.',
-16 => 'خطای داخلی سیستم',
-17 => 'برگشت زدن جزیی تراکنش مجاز نمی باشد.',
-18 => 'IP Address فروشنده نا معتبر است و یا رمز تابع بازگشتی (reverseTransaction) اشتباه است.',
);
if (array_key_exists($status, $translations)) {
throw new InvalidPaymentException($translations[$status], (int)$status);
} else {
throw new InvalidPaymentException('خطای ناشناخته ای رخ داده است.', (int)$status);
}
}
}