diff --git a/README.md b/README.md index e5fcd78..c2a0c55 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ For **Laravel** integration you can use [shetabit/payment](https://github.com/sh - [fanavacard](https://www.fanava.com/) :heavy_check_mark: - [gooyapay](https://gooyapay.ir/) :heavy_check_mark: - [idpay](https://idpay.ir/) :heavy_check_mark: +- [irandargah](https://irandargah.com/) :heavy_check_mark: - [irankish](http://irankish.com/) :heavy_check_mark: - [jibit](https://jibit.ir/) :heavy_check_mark: - [local](#local-driver) :heavy_check_mark: diff --git a/config/payment.php b/config/payment.php index 6dd5592..aaeabe4 100755 --- a/config/payment.php +++ b/config/payment.php @@ -113,6 +113,22 @@ 'sandbox' => false, // set it to true for test environments 'currency' => 'R', //Can be R, T (Rial, Toman) ], + 'irandargah' => [ + /* Normal api */ + 'apiPurchaseUrl' => 'https://dargaah.com/payment', + 'apiPaymentUrl' => 'https://dargaah.com/ird/startpay/', + 'apiVerificationUrl' => 'https://dargaah.com/verification', + + /* Sandbox api */ + 'sandboxApiPurchaseUrl' => ' https://dargaah.com/sandbox/payment', + 'sandboxApiPaymentUrl' => 'https://dargaah.com/sandbox/ird/startpay/', + 'sandboxApiVerificationUrl' => 'https://dargaah.com/sandbox/verification', + + 'sandbox' => false, // Set it to true for test environments + 'merchantId' => '', // Set `TEST` for test environments (sandbox) + 'callbackUrl' => '', + 'currency' => 'R', //Can be R, T (Rial, Toman) + ], 'irankish' => [ 'apiPurchaseUrl' => 'https://ikc.shaparak.ir/api/v3/tokenization/make', 'apiPaymentUrl' => 'https://ikc.shaparak.ir/iuiv3/IPG/Index/', @@ -491,6 +507,7 @@ 'digipay' => \Shetabit\Multipay\Drivers\Digipay\Digipay::class, 'etebarino' => \Shetabit\Multipay\Drivers\Etebarino\Etebarino::class, 'idpay' => \Shetabit\Multipay\Drivers\Idpay\Idpay::class, + 'irandargah' => \Shetabit\Multipay\Drivers\IranDargah\IranDargah::class, 'irankish' => \Shetabit\Multipay\Drivers\Irankish\Irankish::class, 'jibit' => \Shetabit\Multipay\Drivers\Jibit\Jibit::class, 'nextpay' => \Shetabit\Multipay\Drivers\Nextpay\Nextpay::class, diff --git a/src/Drivers/IranDargah/IranDargah.php b/src/Drivers/IranDargah/IranDargah.php new file mode 100644 index 0000000..00dde0c --- /dev/null +++ b/src/Drivers/IranDargah/IranDargah.php @@ -0,0 +1,270 @@ +invoice($invoice); + $this->settings = (object) $settings; + $this->client = new Client(); + } + + /** + * Retrieve data from details using its name. + * + * @return string + */ + private function extractDetails($name) + { + return empty($this->invoice->getDetails()[$name]) ? null : $this->invoice->getDetails()[$name]; + } + + /** + * Purchase Invoice. + * + * @return string + * + * @throws PurchaseFailedException + */ + public function purchase() + { + $data = [ + 'merchantID' => $this->settings->merchantId, + 'amount' => $this->getInvoiceAmount(), + 'callbackURL' => $this->settings->callbackUrl, + 'orderId' => $this->invoice->getUuid(), + 'cardNumber' => $this->extractDetails('cardNumber'), + 'mobile' => $this->extractDetails('mobile'), + 'description' => $this->extractDetails('description'), + ]; + + $response = $this->client->request( + 'POST', + $this->getPurchaseUrl(), + [ + 'form_params' => $data, + 'http_errors' => false, + ] + ); + + $body = json_decode($response->getBody()->getContents(), true); + + if ($body['status'] != 200) { + throw new PurchaseFailedException($this->translateStatus($body['status']), $body['status']); + } + + $this->invoice->transactionId($body['authority']); + + // return the transaction's id + return $this->invoice->getTransactionId(); + } + + /** + * Pay the Invoice + * + * @return RedirectionForm + */ + public function pay(): RedirectionForm + { + $payUrl = $this->getPaymentUrl() . $this->invoice->getTransactionId(); + + return $this->redirectWithForm($payUrl, [], 'GET'); + } + + /** + * Verify payment + * + * @return ReceiptInterface + * + * @throws InvalidPaymentException + */ + public function verify(): ReceiptInterface + { + $paymentCode = Request::input('code'); + + if ($paymentCode != 100) { + throw new InvalidPaymentException($this->translateStatus($paymentCode), $paymentCode); + } + + $data = [ + 'merchantID' => $this->settings->merchantId, + 'authority' => $this->invoice->getTransactionId() ?? Request::input('authority'), + 'amount' => $this->getInvoiceAmount(), + 'orderId' => Request::input('orderId'), + ]; + + $response = $this->client->request( + 'POST', + $this->getVerificationUrl(), + [ + 'json' => $data, + "headers" => [ + 'Content-Type' => 'application/json', + ], + "http_errors" => false, + ] + ); + + $body = json_decode($response->getBody()->getContents(), true); + + if ($body['status'] != 100) { + throw new InvalidPaymentException($this->translateStatus($body['status']), $body['status']); + } + + $refId = $body['refId']; + $receipt = $this->createReceipt($refId); + + $receipt->detail([ + 'message' => $body['message'], + 'status' => $body['status'], + 'refId' => $refId, + 'orderId' => $body['orderId'], + 'cardNumber' => $body['cardNumber'], + ]); + + return $receipt; + } + + /** + * Generate the payment's receipt + * + * @param $referenceId + * + * @return Receipt + */ + public function createReceipt($referenceId) + { + return new Receipt('irandargah', $referenceId); + } + + /** + * Retrieve invoice amount + * + * @return int|float + */ + protected function getInvoiceAmount() + { + return $this->invoice->getAmount() * (strtolower($this->settings->currency) === 't' ? 10 : 1); // convert to rial + } + + /** + * Retrieve purchase url + * + * @return string + */ + protected function getPurchaseUrl(): string + { + return $this->isSandboxMode() + ? $this->settings->sandboxApiPurchaseUrl + : $this->settings->apiPurchaseUrl; + } + + /** + * Retrieve Payment url + * + * @return string + */ + protected function getPaymentUrl(): string + { + return $this->isSandboxMode() + ? $this->settings->sandboxApiPaymentUrl + : $this->settings->apiPaymentUrl; + } + + /** + * Retrieve verification url + * + * @return string + */ + protected function getVerificationUrl(): string + { + return $this->isSandboxMode() + ? $this->settings->sandboxApiVerificationUrl + : $this->settings->apiVerificationUrl; + } + + /** + * Retrieve payment in sandbox mode? + * + * @return bool + */ + protected function isSandboxMode() : bool + { + return $this->settings->sandbox; + } + + /** + * Convert status to a readable message. + * + * @param $status + * + * @return mixed|string + */ + private function translateStatus($status) + { + $translations = [ + '100' => 'تراکنش با موفقیت انجام ‌شده‌ است', + '101' => 'تراکنش قبلا وریفای شده است', + '200' => 'اتصال به درگاه بانک با موفقیت انجام ‌شده است', + '201' => 'در حال پرداخت در درگاه بانک', + '403' => 'کد مرچنت صحیح نمی‌باشد', + '404' => 'تراکنش یافت نشد', + '-1' => 'کاربر از انجام تراکنش منصرف‌ شده است', + '-2' => 'اطلاعات ارسالی صحیح نمی‌باشد', + '-10' => 'مبلغ تراکنش کمتر از ۱۰،۰۰۰ ریال است', + '-11' => 'مبلغ تراکنش با مبلغ پرداخت، یکسان نیست. مبلغ برگشت خورد', + '-12' => 'شماره کارتی که با آن، تراکنش انجام ‌شده است با شماره کارت ارسالی، مغایرت دارد. مبلغ برگشت خورد', + '-13' => 'تراکنش تکراری است', + '-20' => 'شناسه تراکنش یافت‌ نشد', + '-21' => 'مدت زمان مجاز، جهت ارسال به بانک گذشته‌است', + '-22' => 'تراکنش برای بانک ارسال شده است', + '-23' => 'خطا در اتصال به درگاه بانک', + '-30' => 'اشکالی در فرایند پرداخت ایجاد ‌شده است. مبلغ برگشت خورد', + '-31' => 'خطای ناشناخته', + ]; + + $unknownError = 'خطای ناشناخته رخ داده است. در صورت کسر مبلغ از حساب حداکثر پس از 72 ساعت به حسابتان برمیگردد'; + + return array_key_exists($status, $translations) ? $translations[$status] : $unknownError; + } +}