'approved', '01' => 'bank_call', '02' => 'bank_call', '05' => 'reject', '09' => 'try_again', '12' => 'invalid_transaction', '28' => 'reject', '51' => 'insufficient_balance', '54' => 'expired_card', '57' => 'does_not_allow_card_holder', '62' => 'restricted_card', '77' => 'request_rejected', '99' => 'general_error', ]; /** * Transaction Types * * @var array */ public $types = [ 'pay' => 'Auth', 'pre' => 'PreAuth', 'post' => 'PostAuth', ]; /** * Currencies * * @var array */ public $currencies = []; /** * Transaction Type * * @var string */ public $type; /** * API Account * * @var array */ protected $account = []; /** * Order Details * * @var array */ protected $order = []; /** * Credit Card * * @var object */ protected $card; /** * Request * * @var Request */ protected $request; /** * Response Raw Data * * @var object */ protected $data; /** * Processed Response Data * * @var mixed */ public $response; /** * Configuration * * @var array */ protected $config = []; /** * Processed Response Data * * @var mixed */ public $client; /** * EstPos constructor. * * @param array $config * @param mixed $account * @param array $currencies */ public function __construct($config, $account, array $currencies) { $client = new Client(); $this->client = $client; $this->config = $config; $this->account = $account; $this->currencies = $currencies; $this->url = isset($this->config['urls'][$this->account->env]) ? $this->config['urls'][$this->account->env] : $this->config['urls']['production']; $this->gateway = isset($this->config['urls']['gateway'][$this->account->env]) ? $this->config['urls']['gateway'][$this->account->env] : $this->config['urls']['gateway']['production']; return $this; } /** * Create Regular Payment XML * * @return string */ protected function createRegularPaymentXML() { $nodes = [ 'CC5Request' => [ 'Name' => $this->account->username, 'Password' => $this->account->password, 'ClientId' => $this->account->client_id, 'Type' => $this->type, 'IPAddress' => $this->order->ip, 'Email' => $this->order->email, 'OrderId' => $this->order->id, 'UserId' => isset($this->order->user_id) ? $this->order->user_id : null, 'Total' => $this->order->amount, 'Currency' => $this->order->currency, 'Taksit' => $this->order->installment, 'CardType' => isset($this->card->type) ? $this->card->type : null, 'Number' => $this->card->number, 'Expires' => $this->card->month . '/' . $this->card->year, 'Cvv2Val' => $this->card->cvv, 'Mode' => 'P', 'GroupId' => '', 'TransId' => '', 'BillTo' => [ 'Name' => $this->order->name ? $this->order->name : null, ] ] ]; return $this->createXML($nodes, 'ISO-8859-9'); } /** * Create Regular Payment Post XML * * @return string */ protected function createRegularPostXML() { $nodes = [ 'CC5Request' => [ 'Name' => $this->account->username, 'Password' => $this->account->password, 'ClientId' => $this->account->client_id, 'Type' => $this->types[$this->order->transaction], 'OrderId' => $this->order->id, ] ]; return $this->createXML($nodes, 'ISO-8859-9'); } /** * Create 3D Payment XML * @return string */ protected function create3DPaymentXML() { $nodes = [ 'CC5Request' => [ 'Name' => $this->account->username, 'Password' => $this->account->password, 'ClientId' => $this->account->client_id, 'Type' => $this->type, 'IPAddress' => $this->order->ip, 'Email' => $this->order->email, 'OrderId' => $this->order->id, 'UserId' => isset($this->order->user_id) ? $this->order->user_id : null, 'Total' => $this->order->amount, 'Currency' => $this->order->currency, 'Taksit' => $this->order->installment, 'Number' => $this->request->get('md'), 'Expires' => '', 'Cvv2Val' => '', 'PayerTxnId' => $this->request->get('xid'), 'PayerSecurityLevel' => $this->request->get('eci'), 'PayerAuthenticationCode' => $this->request->get('cavv'), 'CardholderPresentCode' => '13', 'Mode' => 'P', 'GroupId' => '', 'TransId' => '', ] ]; if ($this->order->name) { $nodes['BillTo'] = [ 'Name' => $this->order->name, ]; } return $this->createXML($nodes, 'ISO-8859-9'); } /** * Get ProcReturnCode * * @return string|null */ protected function getProcReturnCode() { return isset($this->data->ProcReturnCode) ? (string)$this->data->ProcReturnCode : null; } /** * Get Status Detail Text * * @return string|null */ protected function getStatusDetail() { $proc_return_code = $this->getProcReturnCode(); return $proc_return_code ? (isset($this->codes[$proc_return_code]) ? (string)$this->codes[$proc_return_code] : null) : null; } /** * Create 3D Hash * * @return string */ public function create3DHash() { $hash_str = ''; $hash_str = $this->order->id . $this->order->amount . $this->order->success_url . $this->order->fail_url . $this->type . $this->order->installment . $this->order->rand . $this->account->merchant_pass; return base64_encode(pack('H*', sha1($hash_str))); } /** * Check 3D Hash * * @param array $data * @return bool */ public function check3DHash($data) { $return = false; $responseHash = $data['ResponseHash']; //MerchantID + MerchantPass + OrderId + AuthCode + ProcReturnCode + 3DStatus + ResponseRnd + UserCode $generatedHash = $this->account->merchant_id . $this->account->merchant_pass . $data['OrderId'] . $data['AuthCode'] . $data['ProcReturnCode'] . $data['3DStatus'] . $data['ResponseRnd'] . $this->account->user_code; $generatedHash = base64_encode(pack('H*', sha1($generatedHash))); if ($generatedHash == $responseHash) { $return = true; } return $return; } /** * Regular Payment * * @return $this * @throws GuzzleException */ public function makeRegularPayment() { return false; } /** * Make 3D Payment * * @return $this * @throws GuzzleException */ public function make3DPayment() { return false; } /** * Make 3D Pay Payment * * @return $this */ public function make3DPayPayment() { $this->request = Request::createFromGlobals(); $requestAll = $this->request->request->all(); $ipAddress = $this->request->getClientIp(); /*echo "
";
        print_r($this->order);
        die();*/

        $paymentCheck = null;
        $status = 'declined';
        $transaction_security = 'MPI fallback';
        $errorMessage = null;

        try {

            $requestParam = new \SimpleXMLElement('');

            $requestParam->addChild('MerchantId', $this->account->merchant_id);
            $requestParam->addChild('Password', $this->account->merchant_password);
            $requestParam->addChild('TerminalNo', $this->account->terminal_no);
            $requestParam->addChild('TransactionType', 'Sale');
            $requestParam->addChild('OrderId', $this->order->id);
            $requestParam->addChild('CurrencyAmount', number_format(($requestAll['PurchAmount'] / 100), 2, '.', ''));
            $requestParam->addChild('CurrencyCode', $requestAll['PurchCurrency']);
            $requestParam->addChild('Pan', $requestAll['Pan']);
            $requestParam->addChild('Expiry', $this->order->creditCardYear . $this->order->creditCardMonth);
            $requestParam->addChild('Cvv', $this->order->creditCardYearCvv);
            $requestParam->addChild('ECI', $requestAll['Eci']);
            $requestParam->addChild('CAVV', $requestAll['Cavv']);
            $requestParam->addChild('MpiTransactionId', $requestAll['VerifyEnrollmentRequestId']);
            $requestParam->addChild('ClientIp', $ipAddress);
            $requestParam->addChild('TransactionDeviceSource', 0);

            if (!empty($requestAll['InstallmentCount'])) {
                $requestParam->addChild('NumberOfInstallments', $requestAll['InstallmentCount']);
            }

            $payment = $this->client->request('POST', $this->url, [
                'form_params' => ['prmstr' => $requestParam->asXML()]
            ]);

            $paymentCheck = $this->XMLStringToObject($payment->getBody()->getContents());

            if ($paymentCheck->ResultCode == '0000') {
                $status = 'approved';
            } else {
                $errorMessage = $paymentCheck->ResultDetail;
            }

            if ($paymentCheck->ThreeDSecureType == '2') {
                $transaction_security = 'Full 3D Secure';
            } elseif ($paymentCheck->ThreeDSecureType == '3') {
                $transaction_security = 'Half 3D Secure';
            }

        } catch (Exception $e) {
            Log::error($this->account->bank . ' Error!');
            Log::error($e->getMessage());
        }



        $this->response = (object)[
            'id' => isset($paymentCheck->TransactionId) ? (string)$paymentCheck->TransactionId : null,
            'trans_id' => isset($paymentCheck->TransactionId) ? (string)$paymentCheck->TransactionId : null,
            'auth_code' => isset($paymentCheck->AuthCode) ? (string)$paymentCheck->AuthCode : null,
            'host_ref_num' => isset($paymentCheck->TransactionId) ? (string)$paymentCheck->TransactionId : null,
            'order_id' => isset($paymentCheck->TransactionId) ? (string)$paymentCheck->TransactionId : null,
            'status' => $status,
            'response' => $paymentCheck,
            'transaction_security' => $transaction_security,
            'error_code' => isset($paymentCheck->ResultCode) ? (string)$paymentCheck->ResultCode : null,
            'error_message' => $errorMessage,
            'all' => $paymentCheck
        ];

        /*echo "
";
        print_r($this->response);
        die();*/

        return $this;
    }

    /**
     * Get 3d Form Data
     *
     * @return array
     */
    public function get3DFormData()
    {
        $threeDFormData = [];

        try {

            if ($this->order) {

                $threeDCheckParam = [
                    'Pan' => $this->card->number,
                    'ExpiryDate' => $this->getCardExpDate(),
                    'PurchaseAmount' => number_format(($this->order->amount * 100 / 100), 2, '.', ''),
                    'Currency' => $this->order->currency,
                    'BrandName' => null,
                    'VerifyEnrollmentRequestId' => $this->order->id,
                    'MerchantId' => $this->account->merchant_id,
                    'MerchantPassword' => $this->account->merchant_password,
                    'SuccessUrl' => $this->order->success_url,
                    'FailUrl' => $this->order->success_url,
                ];

                $response = $this->client->request('POST', $this->gateway, [
                    'form_params' => $threeDCheckParam
                ]);

                $threeDCheck = $this->XMLStringToObject($response->getBody()->getContents());

                if ($threeDCheck->MessageErrorCode != 200) {
                    throw new Exception($threeDCheck->MessageErrorCode . ' - ' . $threeDCheck->ErrorMessage);
                }

                $threeDFormData = [
                    'status' => $threeDCheck->Message->VERes->Status,
                    'gateway' => $threeDCheck->Message->VERes->ACSUrl,
                    'success_url' => $this->order->success_url,
                    'fail_url' => $this->order->success_url,
                    'inputs' => [
                        'PaReq' => $threeDCheck->Message->VERes->PaReq,
                        'TermUrl' => $threeDCheck->Message->VERes->TermUrl,
                        'MD' => $threeDCheck->Message->VERes->MD
                    ]
                ];

                if ($threeDFormData['status'] != 'Y') {
                    throw new Exception('3D Secure is not supported for this card.');
                }

            }

        } catch (Exception $e) {
            Log::error($this->account->bank . ' Error!');
            Log::error($e->getMessage());
            $threeDFormData = [];
        }

        return $threeDFormData;
    }

    /**
     * Send contents to WebService
     *
     * @param $contents
     * @return $this
     * @throws GuzzleException
     */
    public function send($contents)
    {
        $client = new Client();

        $response = $client->request('POST', $this->url, [
            'body' => $contents
        ]);

        $this->data = $this->XMLStringToObject($response->getBody()->getContents());

        return $this;
    }

    /**
     * Prepare Order
     *
     * @param object $order
     * @param object null $card
     * @return mixed
     * @throws UnsupportedTransactionTypeException
     */
    public function prepare($order, $card = null)
    {
        $this->type = $this->types['pay'];
        if (isset($order->transaction)) {
            if (array_key_exists($order->transaction, $this->types)) {
                $this->type = $this->types[$order->transaction];
            } else {
                throw new UnsupportedTransactionTypeException('Unsupported transaction type!');
            }
        }

        $this->order = $order;
        $this->card = $card;

        $this->order->installment = $this->order->installment == 0 ? 0 : $this->order->installment;
    }

    /**
     * Make Payment
     *
     * @param object $card
     * @return mixed
     * @throws UnsupportedPaymentModelException
     * @throws GuzzleException
     */
    public function payment($card)
    {
        $this->card = $card;

        $model = 'regular';
        if (isset($this->account->model) && $this->account->model) {
            $model = $this->account->model;
        }

        if ($model == 'regular') {
            $this->makeRegularPayment();
        } elseif ($model == '3d') {
            $this->make3DPayment();
        } elseif ($model == '3d_pay') {
            $this->make3DPayPayment();
        } else {
            throw new UnsupportedPaymentModelException();
        }

        return $this;
    }

    /**
     * Refund Order
     *
     * @param array $meta
     * @return $this
     * @throws GuzzleException
     */
    public function refund(array $meta)
    {
        return false;
    }

    /**
     * Cancel Order
     *
     * @param array $meta
     * @return $this
     * @throws GuzzleException
     */
    public function cancel(array $meta)
    {
        return false;
    }

    /**
     * Order Status
     *
     * @param array $meta
     * @return $this
     * @throws GuzzleException
     */
    public function status(array $meta)
    {
        return false;
    }

    /**
     * Order History
     *
     * @param array $meta
     * @return $this
     * @throws GuzzleException
     */
    public function history(array $meta)
    {
        return false;
    }

    /**
     * @return array
     */
    public function getConfig()
    {
        return $this->config;
    }

    /**
     * @return mixed
     */
    public function getAccount()
    {
        return $this->account;
    }

    /**
     * @return array
     */
    public function getCurrencies()
    {
        return $this->currencies;
    }

    /**
     * @return mixed
     */
    public function getOrder()
    {
        return $this->order;
    }

    /**
     * @return mixed
     */
    public function getCard()
    {
        return $this->card;
    }

    /**
     * @return string|null
     */
    public function getCardCode()
    {
        $card_type = null;
        if (isset($this->card->type)) {
            if ($this->card->type == 'visa') {
                $card_type = '0';
            } elseif ($this->card->type == 'master') {
                $card_type = '1';
            } elseif ($this->card->type == '1' || $this->card->type == '2') {
                $card_type = $this->card->type;
            }
        }
        return $card_type;
    }

    protected function getCardExpDate()
    {
        $year = (string)substr($this->card->year, 2, 2);
        $month = (string)substr($this->card->month, 0, 2);

        return (string)$year . $month;
    }


}