<?php
/**
* @package XenCentral Framework
* @author Skydevelop EU
* @copyright Drnoyan & Nalyan LDA, Portugal, EU
* @license http://www.dnf.pt/eula.html
* @link http://www.skydevelop.com
* @version 1.4.1
* @revision 125
*/


class XenCentral_PaymentApi_Methods_Paypal extends XenCentral_PaymentApi_Method
{
    protected $_validSettings = array(
        'business' => array(
            'title' => 'PayPal Email',
            'required' => 1,
            'field' => 1
        )
    );

    protected $_validFields = array(
        'currency_code' => array(
            'title' => 'Currency',
            'required' => 0,
            'default' => 'USD'
        ),
        'amount' => array(
            'title' => 'Amount',
            'required' => 1
        ),
        'item_name' => array(
            'title' => 'Item Name',
            'required' => 1
        ),
        'return' => array(
            'title' => 'Return URL',
            'required' => 0
        ),
        'item_number' => array(
            'title' => 'Item Number',
            'required' => 0
        ),
        'cancel_return' => array(
            'title' => 'Cancel Return URL',
            'required' => 0
        ),
        'notify_url' => array(
            'title' => 'Notify URL',
            'required' => 0
        ),
        'cmd' => array(
            'title' => 'Command',
            'required' => 0,
            'default' => '_xclick'
        ),
        'rm' => array(
            'title' => 'Return Method',
            'required' => 0,
            'default' => 2
        )
    );

    protected function _generateTransactionHash()
    {
        return md5($this->_info['item_name'] . $this->_info['item_number'] . $this->_info['amount'] . rand(1, time()));
    }

    protected function _validateSettings()
    {
        if (!$this->_settings['business']) {
            $this->_setError('paypal_email', "Please specify seller's PayPal email address.");
            return false;
        }

        return parent::_validateSettings();
    }

    protected function _validateInfo()
    {
        if (!$this->_info['amount']) {
            $this->_setError('amount', "Please specfiy payment amount");
            return false;
        }

        if (!$this->_info['currency_code']) {
            $this->_setError('currency_code', "Please specify currency code");
            return false;
        }

        if (!$this->_info['item_name']) {
            $this->_setError('item_name', "Please specify item name");
            return false;
        }

        return parent::_validateInfo();
    }

    protected function _getDebugFormURL()
    {
        return 'https://www.sandbox.paypal.com/cgi-bin/webscr';
    }

    protected function _getLiveFormURL()
    {
        return 'https://www.paypal.com/cgi-bin/webscr';
    }

    protected function _getFormMethod()
    {
        return 'POST';
    }

    protected function _getFormHiddenFields()
    {
        $this->_info['custom'] = $this->_additionalInfo['transactionhash'];

        return XenCentral_Framework_Helper_Html::constructHiddenCode($this->_info);
    }

    public function getMethodIdentifier($formatted = false)
    {
        if ($formatted) {
            return 'PayPal';
        }

        return 'paypal';
    }

    protected function _getTransactionHashFromRequest()
    {
        if ($this->getApi()->getRequest()->getParam('custom')) {
            return $this->_validatePaymentHash($this->getApi()->getRequest()->getParam('custom'));
        }
        return false;
    }

    protected function _validateRequest()
    {
        $serialized=serialize($_POST);
        // post back to paypal to validate the request
        $url = $this->_getFormURL();

        $postContent = array();

        $postContent[] = 'cmd=_notify-validate';

        foreach ($_POST as $key => $val) {
            $postContent[] = $key . '=' . urlencode($val);
        }

        $postContent = implode('&', $postContent);

        $connectionErrors = array();

        $result = self::remoteRequest($url, $postContent, $connectionErrors);

        if ($result === false) {
            $this->_setError('connection_failed', implode("\n\n", $connectionErrors));
            return false;
        }

        if ($result == 'VERIFIED' && $this->getApi()->getRequest()->getParam('business') == $this->getSetting('business')) {
            $mc_gross = doubleval($this->getApi()->getRequest()->getParam('mc_gross', 0));
            $tax = doubleval($this->getApi()->getRequest()->getParam('tax', 0));

            if ($tax > 0) {
                $mc_gross -= $tax;
            }

            if (
            ($this->getApi()->getRequest()->getParam('txn_type') == 'web_accept' OR $this->getApi()->getRequest()->getParam('txn_type') == 'subscr_payment')
            ) {
                if ($mc_gross == doubleval($this->_info['amount'])) {
                    return true;
                } else {
                    $this->_setError('invalid_payment_amount', 'Invalid payment amount detected');
                }
            } else if (
                    (
                            $this->getApi()->getRequest()->getParam('payment_status') == 'Reversed'
                            OR $this->getApi()->getRequest()->getParam('payment_status') == 'Refunded'
                    )
                    OR
                    (
                            $this->getApi()->getRequest()->getParam('payment_status') == 'Pending'
                            AND
                            $this->getApi()->getRequest()->getParam('reason_code') == 'refund'
                    )
            ) {
                // we handle refunds as well

                // this is for _setTypeFromRequest
                $this->getApi()->getRequest()->setParam('payment_status', 'Refunded');
                return true;
            } else {
                if ($this->getApi()->getRequest()->getParam('payment_status') == 'Pending') {
                    // this is most likely some kind of intermediate state for refund, so return success response anyway
                    return true;
                }
                $this->_setError('unhandled_payment_status_or_type', 'Unhandled payment.');
            }
            return false;
        }

        $this->_setError('invalid_request', 'Could not validate PayPal IPN request - ' . "$result - $url" . '.');

        return false;
    }

    public function sendSuccessResponse()
    {
        if (headers_sent($file, $line)) {
            return false;
        }
        $status_code = '200 OK';

        // Paypal likes to get told its message has been received
        if (defined('SAPI_NAME') && (SAPI_NAME == 'cgi' or SAPI_NAME == 'cgi-fcgi')) {
            header('Status: ' . $status_code);
        } else {
            header('HTTP/1.1 ' . $status_code);
        }
        return true;
    }

    public function sendFailResponse()
    {
        if (headers_sent($file, $line)) {
            return false;
        }

        if ($this->getDebugMode()) {
            return $this->sendSuccessResponse();
        }
        $status_code = '503 Service Unavailable';
        // Paypal likes to get told its message has been received
        if (defined('SAPI_NAME') && (SAPI_NAME == 'cgi' or SAPI_NAME == 'cgi-fcgi')) {
            header('Status: ' . $status_code);
        } else {
            header('HTTP/1.1 ' . $status_code);
        }
        return true;
    }

    protected function _setTransactionIdFromRequest()
    {
        return $this->setTransactionId($this->getApi()->getRequest()->getParam('txn_id'));
    }

    protected function _setTypeFromRequest()
    {
        if ($this->getApi()->getRequest()->getParam('txn_type') == 'web_accept' and $this->getApi()->getRequest()->getParam('payment_status') == 'Completed') {
            $this->setType('payment');
        } else if ($this->getApi()->getRequest()->getParam('payment_status') == 'Pending') {
            $this->setType('pending');
        } else if ($this->getApi()->getRequest()->getParam('payment_status') == 'Reversed' or $this->getApi()->getRequest()->getParam('payment_status') == 'Refunded') {
            $this->setType('refund');
        } else {
            $this->setType('unkown type');
        }
    }

    /**
     * PayPal Email
     * @Required
     * @isField
     */
    function setSettingBusiness($value)
    {
        $this->setSetting('business', $value);
    }

    /**
     * Currency
     * @default USD
     */
    function setFieldCurrencyCode($value)
    {
        $this->setField('currency_code', $value);
    }

    /**
     * Amount
     * @Required
     */
    function setFieldAmount($value)
    {
        $this->setField('amount', $value);
    }

    /**
     * Item Name
     * @Required
     */
    function setFieldItemName($value)
    {
        $this->setField('item_name', $value);
    }

    /**
     * Return URL
     */
    function setFieldReturn($value)
    {
        $this->setField('return', $value);
    }

    /**
     * Item Number
     */
    function setFieldItemNumber($value)
    {
        $this->setField('item_number', $value);
    }

    /**
     * Cancel Return URL
     */
    function setFieldCancelReturn($value)
    {
        $this->setField('cancel_return', $value);
    }

    /**
     * Notify URL
     */
    function setFieldNotifyUrl($value)
    {
        $this->setField('notify_url', $value);
    }

    /**
     * Command
     * @default _xclick
     */
    function setFieldCmd($value)
    {
        $this->setField('cmd', $value);
    }

    /**
     * Return Method
     * @default 2
     */
    function setFieldRm($value)
    {
        $this->setField('rm', $value);
    }
}