Skip to content

Commit

Permalink
Add Custom Methods to Digipay Gateway (#231)
Browse files Browse the repository at this point in the history
* [fix] update error message, and ensure variable exist

* [feat] update api url and define suburl inside of driver

* [feat] add custom method reverse and deliver for digipay gateway

* [fix] update logic to sprate condition

* [feat] update deriver method

* [style] fix style

* [fix] fix methods
  • Loading branch information
alissn committed Jul 11, 2024
1 parent b8ef24a commit 1fb4410
Show file tree
Hide file tree
Showing 2 changed files with 233 additions and 40 deletions.
4 changes: 1 addition & 3 deletions config/payment.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,7 @@
'cumulativeDynamicPayStatus' => false,
],
'digipay' => [
'apiOauthUrl' => 'https://api.mydigipay.com/digipay/api/oauth/token',
'apiPurchaseUrl' => 'https://api.mydigipay.info/digipay/api/tickets/business',
'apiVerificationUrl' => 'https://api.mydigipay.com/digipay/api/purchases/verify/',
'apiPaymentUrl' => 'https://api.mydigipay.com', // with out '/' at the end
'username' => 'username',
'password' => 'password',
'client_id' => '',
Expand Down
269 changes: 232 additions & 37 deletions src/Drivers/Digipay/Digipay.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

namespace Shetabit\Multipay\Drivers\Digipay;

use DateTime;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\RequestOptions;
use Shetabit\Multipay\Abstracts\Driver;
use Shetabit\Multipay\Contracts\ReceiptInterface;
Expand All @@ -17,6 +17,15 @@

class Digipay extends Driver
{
const VERSION = '2022-02-02';
const OAUTH_URL = '/digipay/api/oauth/token';
const PURCHASE_URL = '/digipay/api/tickets/business';
const VERIFY_URL = '/digipay/api/purchases/verify/';
const REVERSE_URL = '/digipay/api/reverse';
const DELIVER_URL = '/digipay/api/purchases/deliver';
const REFUNDS_CONFIG = '/digipay/api/refunds/config';
const REFUNDS_REQUEST = '/digipay/api/refunds';

/**
* Digipay Client.
*
Expand Down Expand Up @@ -54,14 +63,11 @@ class Digipay extends Driver
/**
* Digipay 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;
$this->settings = (object) $settings;
$this->client = new Client();
$this->oauthToken = $this->oauth();
}
Expand All @@ -79,9 +85,9 @@ public function purchase(): string
* @see https://docs.mydigipay.com/upg.html#_request_fields_2
*/
$data = [
'amount' => $this->invoice->getAmount() * ($this->settings->currency == 'T' ? 10 : 1),
'cellNumber' => $phone,
'providerId' => $this->invoice->getUuid(),
'amount' => $this->invoice->getAmount() * ($this->settings->currency == 'T' ? 10 : 1),
'cellNumber' => $phone,
'providerId' => $this->invoice->getUuid(),
'callbackUrl' => $this->settings->callbackUrl,
];

Expand All @@ -106,15 +112,15 @@ public function purchase(): string
->client
->request(
'POST',
$this->settings->apiPurchaseUrl,
$this->settings->apiPaymentUrl.self::PURCHASE_URL,
[
RequestOptions::BODY => json_encode($data),
RequestOptions::QUERY => ['type' => $digipayType],
RequestOptions::HEADERS => [
RequestOptions::BODY => json_encode($data),
RequestOptions::QUERY => ['type' => $digipayType],
RequestOptions::HEADERS => [
'Agent' => $this->invoice->getDetail('agent') ?? 'WEB',
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $this->oauthToken,
'Digipay-Version' => '2022-02-02',
'Content-Type' => 'application/json',
'Authorization' => 'Bearer '.$this->oauthToken,
'Digipay-Version' => self::VERSION,
],
RequestOptions::HTTP_ERRORS => false,
]
Expand Down Expand Up @@ -153,12 +159,12 @@ public function verify(): ReceiptInterface

$response = $this->client->request(
'POST',
$this->settings->apiVerificationUrl . $tracingId,
$this->settings->apiPaymentUrl.self::VERIFY_URL.$tracingId,
[
RequestOptions::QUERY => ['type' => $digipayTicketType],
RequestOptions::HEADERS => [
"Accept" => "application/json",
"Authorization" => "Bearer " . $this->oauthToken,
RequestOptions::QUERY => ['type' => $digipayTicketType],
RequestOptions::HEADERS => [
'Accept' => 'application/json',
'Authorization' => 'Bearer '.$this->oauthToken,
],
RequestOptions::HTTP_ERRORS => false,
]
Expand All @@ -183,23 +189,23 @@ protected function oauth()
->client
->request(
'POST',
$this->settings->apiOauthUrl,
$this->settings->apiPaymentUrl.self::OAUTH_URL,
[
RequestOptions::HEADERS => [
'Authorization' => 'Basic ' . base64_encode("{$this->settings->client_id}:{$this->settings->client_secret}"),
RequestOptions::HEADERS => [
'Authorization' => 'Basic '.base64_encode("{$this->settings->client_id}:{$this->settings->client_secret}"),
],
RequestOptions::MULTIPART => [
RequestOptions::MULTIPART => [
[
"name" => "username",
"contents" => $this->settings->username,
'name' => 'username',
'contents' => $this->settings->username,
],
[
"name" => "password",
"contents" => $this->settings->password,
'name' => 'password',
'contents' => $this->settings->password,
],
[
"name" => "grant_type",
"contents" => 'password',
'name' => 'grant_type',
'contents' => 'password',
],
],
RequestOptions::HTTP_ERRORS => false,
Expand All @@ -208,30 +214,219 @@ protected function oauth()

if ($response->getStatusCode() != 200) {
if ($response->getStatusCode() == 401) {
throw new PurchaseFailedException("خطا نام کاربری یا رمز عبور شما اشتباه می باشد.");
throw new PurchaseFailedException('خطا نام کاربری یا رمز عبور شما اشتباه میباشد.');
} else {
throw new PurchaseFailedException("خطا در هنگام احراز هویت.");
throw new PurchaseFailedException('خطا در هنگام احراز هویت.');
}
}

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

$this->oauthToken = $body['access_token'];

return $body['access_token'];
}

/**
* @return string
* @see https://docs.mydigipay.com/upg.html#_purchase_reverse
*
* @throws PurchaseFailedException
*/
public function getPaymentUrl(): string
public function reverse()
{
return $this->paymentUrl;
if (is_null($digipayTicketType = $this->invoice->getDetail('type'))) {
throw new PurchaseFailedException('"type" is required for this method.');
}

if (is_null($trackingCode = $this->invoice->getDetail('trackingCode'))) {
throw new PurchaseFailedException('"trackingCode" is required for this method.');
}

$data = [
'trackingCode' => $trackingCode,
'providerId' => $this->invoice->getTransactionId() ?? $this->invoice->getDetail('providerId') ?? $this->invoice->getUuid(),
];

$response = $this
->client
->request(
'POST',
$this->settings->apiPaymentUrl.self::REVERSE_URL,
[
RequestOptions::BODY => json_encode($data),
RequestOptions::QUERY => ['type' => $digipayTicketType],
RequestOptions::HEADERS => [
'Content-Type' => 'application/json;charset=UTF-8',
'Authorization' => 'Bearer '.$this->oauthToken,
],
RequestOptions::HTTP_ERRORS => false,
]
);

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

if ($response->getStatusCode() != 200 || $body['result']['code'] != 0) {
$message = $body['result']['message'] ?? 'خطا در هنگام درخواست برای برگشت وجه رخ داده است.';
throw new InvalidPaymentException($message, (int) $response->getStatusCode());
}

return $body;
}

/**
* @param string $paymentUrl
* @see https://docs.mydigipay.com/upg.html#_purchase_delivery
*
* @throws PurchaseFailedException
*/
public function setPaymentUrl(string $paymentUrl): void
public function deliver()
{
if (empty($type = $this->invoice->getDetail('type'))) {
throw new PurchaseFailedException('"type" is required for this method.');
}

if (!in_array($type, [5, 13])) {
throw new PurchaseFailedException('This method is not supported for this type.');
}

if (empty($invoiceNumber = $this->invoice->getDetail('invoiceNumber'))) {
throw new PurchaseFailedException('"invoiceNumber" is required for this method.');
}

if (empty($deliveryDate = $this->invoice->getDetail('deliveryDate'))) {
throw new PurchaseFailedException('"deliveryDate" is required for this method.');
}

if (!DateTime::createFromFormat('Y-m-d', $deliveryDate)) {
throw new PurchaseFailedException('"deliveryDate" must be a valid date with format Y-m-d.');
}

if (empty($trackingCode = $this->invoice->getDetail('trackingCode'))) {
throw new PurchaseFailedException('"trackingCode" is required for this method.');
}

if (empty($products = $this->invoice->getDetail('products'))) {
throw new PurchaseFailedException('"products" is required for this method.');
}

if (!is_array($products)) {
throw new PurchaseFailedException('"products" must be an array.');
}

$data = [
'invoiceNumber' => $invoiceNumber,
'deliveryDate' => $deliveryDate,
'trackingCode' => $trackingCode,
'products' => $products,
];

$response = $this
->client
->request(
'POST',
$this->settings->apiPaymentUrl.self::DELIVER_URL,
[
RequestOptions::BODY => json_encode($data),
RequestOptions::QUERY => ['type' => $type],
RequestOptions::HEADERS => [
'Content-Type' => 'application/json;charset=UTF-8',
'Authorization' => 'Bearer '.$this->oauthToken,
],
RequestOptions::HTTP_ERRORS => false,
]
);

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

if ($response->getStatusCode() != 200 || $body['result']['code'] != 0) {
$message = $body['result']['message'] ?? 'خطا در هنگام درخواست برای تحویل کالا رخ داده است.';
throw new InvalidPaymentException($message, (int) $response->getStatusCode());
}

return $body;
}

public function getRefundConfig()
{
$response = $this->client->request(
'POST',
$this->settings->apiPaymentUrl.self::REFUNDS_CONFIG,
[
RequestOptions::HEADERS => [
'Accept' => 'application/json',
'Authorization' => 'Bearer '.$this->oauthToken,
],
RequestOptions::HTTP_ERRORS => false,
]
);

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

if ($response->getStatusCode() != 200 || $body['result']['code'] != 0) {
$message = $body['result']['message'] ?? 'خطا در هنگام درخواست برای دریافت تنظیمات مرجوعی رخ داده است.';
throw new InvalidPaymentException($message, (int) $response->getStatusCode());
}

$certFile = $response['certFile'];

return $certFile;
}

public function refundTransaction()
{
if (empty($type = $this->invoice->getDetail('type'))) {
throw new PurchaseFailedException('"type" is required for this method.');
}

if (empty($providerId = $this->invoice->getDetail('providerId'))) {
throw new PurchaseFailedException('"providerId" is required for this method.');
}

if (empty($amount = $this->invoice->getDetail('amount'))) {
throw new PurchaseFailedException('"amount" is required for this method.');
}

if (empty($saleTrackingCode = $this->invoice->getDetail('saleTrackingCode'))) {
throw new PurchaseFailedException('"saleTrackingCode" is required for this method.');
}

$data = [
'providerId' => $providerId,
'amount' => $amount,
'saleTrackingCode' => $saleTrackingCode,
];

$response = $this
->client
->request(
'POST',
$this->settings->apiPaymentUrl.self::REFUNDS_REQUEST,
[
RequestOptions::BODY => json_encode($data),
RequestOptions::QUERY => ['type' => $type],
RequestOptions::HEADERS => [
'Content-Type' => 'application/json;charset=UTF-8',
'Authorization' => 'Bearer '.$this->oauthToken,
],
RequestOptions::HTTP_ERRORS => false,
]
);

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

if ($response->getStatusCode() != 200 || $body['result']['code'] != 0) {
$message = $body['result']['message'] ?? 'خطا در هنگام درخواست مرجوعی تراکنش رخ داده است.';
throw new InvalidPaymentException($message, (int) $response->getStatusCode());
}

return $body;
}

private function getPaymentUrl(): string
{
return $this->paymentUrl;
}

private function setPaymentUrl(string $paymentUrl): void
{
$this->paymentUrl = $paymentUrl;
}
Expand Down

0 comments on commit 1fb4410

Please sign in to comment.