File: /var/www/school/wp-content/plugins/zarinpal-woocommerce-payment-gateway/ZarinpalHelperClass.php
<?php
class ZarinpalHelperClass {
    private $merchantId;
    private $sandbox;
    private $baseUrl;
    private $redirectUrl;
    private $userAgent;
    private $graphqlUrl;
    private $accessToken;
    public function __construct($merchantId, $sandbox = false, $accessToken = '') {
        $this->merchantId = $merchantId;
        $this->sandbox = $sandbox;
        $this->baseUrl = $sandbox
            ? 'https://sandbox.zarinpal.com/pg/v4/payment/'
            : 'https://payment.zarinpal.com/pg/v4/payment/';
        $this->redirectUrl = $sandbox
            ? 'https://sandbox.zarinpal.com/pg/StartPay/'
            : 'https://payment.zarinpal.com/pg/StartPay/';
        $this->userAgent = 'ZarinPalSdk/v1 WooCommerce Plugin/v.5.0.14' . ' (WooCommerce ' . WC()->version . '; WordPress ' . get_bloginfo('version') . '; PHP ' . PHP_VERSION . ')';
        $this->graphqlUrl = 'https://next.zarinpal.com/api/v4/graphql';
        $this->accessToken = $accessToken;
    }
    public function requestPayment($amount, $callbackUrl, $description, $metadata = array(), $invoices = array(), $referrer_id = null) {
        $data = array(
            'merchant_id' => $this->merchantId,
            'amount' => $amount,
            'callback_url' => $callbackUrl,
            'description' => $description,
            'metadata' => $metadata,
            'invoices' => $invoices,
            'referrer_id' => $referrer_id,
        );
        $data = $this->recursive_array_filter($data);
        $response = $this->sendRequest('request.json', $data);
        if (isset($response['data']['code']) && $response['data']['code'] == 100) {
            return $response['data']['authority'];
        } else {
            $errorMessage = $response['errors']['message'] ?? 'خطای ناشناخته';
            throw new Exception($errorMessage);
        }
    }
    public function verifyPayment($authority, $amount) {
        $data = array(
            'merchant_id' => $this->merchantId,
            'authority' => $authority,
            'amount' => $amount,
        );
        $response = $this->sendRequest('verify.json', $data);
        if (isset($response['data']['code']) && ($response['data']['code'] == 100 || $response['data']['code'] == 101)) {
            return $response['data'];
        } else {
            $errorMessage = $response['errors']['message'] ?? 'خطای ناشناخته';
            throw new Exception($errorMessage);
        }
    }
    public function getRedirectUrl($authority) {
        return $this->redirectUrl . $authority;
    }
    public function refundPayment($session_id, $amount, $description = '', $method = 'PAYA', $reason = 'CUSTOMER_REQUEST') {
        $query = [
            'query' => '
                mutation AddRefund($session_id: ID!, $amount: BigInteger!, $description: String, $method: InstantPayoutActionTypeEnum, $reason: RefundReasonEnum) {
                    resource: AddRefund(
                        session_id: $session_id,
                        amount: $amount,
                        description: $description,
                        method: $method,
                        reason: $reason
                    ) {
                        terminal_id,
                        id,
                        amount,
                        timeline {
                            refund_amount,
                            refund_time,
                            refund_status
                        }
                    }
                }
            ',
            'variables' => [
                'session_id' => $session_id,
                'amount' => $amount,
                'description' => $description,
                'method' => $method,
                'reason' => $reason,
            ],
        ];
        $response = $this->sendGraphQLRequest($query);
        if (isset($response['data']['resource'])) {
            return $response['data']['resource'];
        } else {
            $errorMessage = $response['errors'][0]['message'] ?? 'خطای ناشناخته';
            throw new Exception($errorMessage);
        }
    }
    public function getTransactions($authority) {
        $query = [
            'query' => '
            query Sessions(
                $terminal_id: ID,
                $filter: FilterEnum,
                $id: ID,
                $reference_id: String,
                $rrn: String,
                $card_pan: String,
                $email: String,
                $mobile: CellNumber,
                $description: String,
                $limit: Int,
                $offset: Int
            ) {
                Session(
                    terminal_id: $terminal_id,
                    filter: $filter,
                    id: $id,
                    reference_id: $reference_id,
                    rrn: $rrn,
                    card_pan: $card_pan,
                    email: $email,
                    mobile: $mobile,
                    description: $description,
                    limit: $limit,
                    offset: $offset
                ) {
                    id
                    authority
                    amount
                    fee
                    status
                    description
                    created_at
                    reference_id
                    reconciled_at
                    session_tries {
                        card_pan
                        rrn
                        payer_ip
                    }
                }
            }
        ',
            'variables' => [
                'authority' => $authority
            ],
        ];
        $response = $this->sendGraphQLRequest($query);
        if (isset($response['data']['Session'])) {
            return $response['data']['Session'];
        } else {
            $errorMessage = $response['errors'][0]['message'] ?? 'خطای ناشناخته';
            throw new Exception($errorMessage);
        }
    }
    public function unverifiedTransactions() {
        $data = array(
            'merchant_id' => $this->merchantId,
        );
        $response = $this->sendRequest('unVerified.json', $data);
        if (isset($response['data']['code']) && $response['data']['code'] == 100) {
            return $response['data']['authorities'];
        } else {
            $errorMessage = $response['errors']['message'] ?? 'خطای ناشناخته';
            throw new Exception($errorMessage);
        }
    }
    public function reversePayment($authority) {
        $data = array(
            'merchant_id' => $this->merchantId,
            'authority' => $authority,
        );
        $response = $this->sendRequest('reverse.json', $data);
        if (isset($response['data']['code']) && $response['data']['code'] == 100) {
            return true;
        } else {
            $errorMessage = $response['errors']['message'] ?? 'خطای ناشناخته';
            throw new Exception($errorMessage);
        }
    }
    public function inquiryPayment($authority) {
        $data = array(
            'merchant_id' => $this->merchantId,
            'authority' => $authority,
        );
        $response = $this->sendRequest('inquiry.json', $data);
        if (isset($response['data']['code']) && $response['data']['code'] == 100) {
            return $response['data'];
        } else {
            $errorMessage = $response['errors']['message'] ?? 'خطای ناشناخته';
            throw new Exception($errorMessage);
        }
    }
    public function calculateFee($amount, $currency = 'IRR') {
        $data = array(
            'merchant_id' => $this->merchantId,
            'amount' => $amount,
            'currency' => $currency,
        );
        
        $response = $this->sendRequest('feeCalculation.json', $data);
        
        if (isset($response['data']['code']) && $response['data']['code'] == 100) {
            return $response['data'];
        } else {
            $errorMessage = $response['errors']['message'] ?? 'خطای ناشناخته';
            throw new Exception($errorMessage);
        }
    }
    private function sendGraphQLRequest($query) {
        $url = $this->graphqlUrl;
        $args = array(
            'body' => json_encode($query),
            'headers' => array(
                'Content-Type' => 'application/json',
                'User-Agent' => $this->userAgent,
                'Authorization' => $this->accessToken,
            ),
            'timeout' => 15,
            'data_format' => 'body',
        );
        $response = wp_remote_post($url, $args);
        if (is_wp_error($response)) {
            throw new Exception('خطا در ارتباط با سرور: ' . $response->get_error_message());
        }
        $response_body = wp_remote_retrieve_body($response);
        $result = json_decode($response_body, true);
        if (isset($result['errors'])) {
            throw new Exception($result['errors'][0]['message']);
        }
        return $result;
    }
    private function sendRequest($endpoint, $data) {
        $url = $this->baseUrl . $endpoint;
        $args = array(
            'body' => json_encode($data),
            'headers' => array(
                'Content-Type' => 'application/json',
                'User-Agent' => $this->userAgent,
            ),
            'timeout' => 15,
            'data_format' => 'body',
        );
        $response = wp_remote_post($url, $args);
        if (is_wp_error($response)) {
            throw new Exception('خطا در ارتباط با سرور: ' . $response->get_error_message());
        }
        $response_body = wp_remote_retrieve_body($response);
        $result = json_decode($response_body, true);
        return $result;
    }
    private function recursive_array_filter($array) {
        foreach ($array as $key => &$value) {
            if (is_array($value)) {
                $value = $this->recursive_array_filter($value);
                if (empty($value)) {
                    unset($array[$key]);
                }
            } else {
                if (is_null($value) || $value === '') {
                    unset($array[$key]);
                }
            }
        }
        return $array;
    }
}