<?php if (! defined('BASEPATH')) { exit('No direct script access allowed'); }



/*

 * CI-Merchant Library for Buckaroo

 *

 * Copyright (c) 2012 Denver Sessink, a&m impact internetdiensten bv <d.sessink@am-impact.nl>

 *

 * Permission is hereby granted, free of charge, to any person obtaining a copy

 * of this software and associated documentation files (the "Software"), to deal

 * in the Software without restriction, including without limitation the rights

 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

 * copies of the Software, and to permit persons to whom the Software is

 * furnished to do so, subject to the following conditions:

 *

 * The above copyright notice and this permission notice shall be included in

 * all copies or substantial portions of the Software.

 *

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

 * THE SOFTWARE.

 */



/*

 * Buckaroo (Dutch payment gateway)

 *

 * Payment processing using Buckaroo

 * Documentation used: "BPE 3.0 gateway HTML.1.00.pdf"

 */

class Merchant_buckaroo extends Merchant_driver

{

    const PROCESS_URL      = 'https://checkout.buckaroo.nl/html/';

    const PROCESS_URL_TEST = 'https://testcheckout.buckaroo.nl/html/';



    const BUCKAROO_STATUSCODE_PAYMENT_SUCCESS            = 190;

    const BUCKAROO_STATUSCODE_PAYMENT_FAILURE            = 490;

    const BUCKAROO_STATUSCODE_VALIDATION_ERROR           = 491;

    const BUCKAROO_STATUSCODE_TECHNICAL_ERROR            = 492;

    const BUCKAROO_STATUSCODE_PAYMENT_REJECTED           = 690;

    const BUCKAROO_STATUSCODE_WAITING_FOR_USER_INPUT     = 790;

    const BUCKAROO_STATUSCODE_WAITING_FOR_PROCESSOR      = 791;

    const BUCKAROO_STATUSCODE_WAITING_ON_CONSUMER_ACTION = 792;

    const BUCKAROO_STATUSCODE_PAYMENT_ON_HOLD            = 793;

    const BUCKAROO_STATUSCODE_CANCELLED_BY_CONSUMER      = 890;

    const BUCKAROO_STATUSCODE_CANCELLED_BY_MERCHANT      = 891;



    public function default_settings()

    {

        return array(

            'website_key' => '',     // Required // The unique key of the website for which the payment is placed.

            'secret_key' => '',     // Required // Pre-shared secret key which is used at calculating the digital signature

            'test_mode'  => TRUE,

        );

    }



    /**

     * Sends the user to the Buckaroo payment gateway

     */

    public function purchase()

    {

        $request_array = $this->_build_purchase();

        $this->post_redirect($this->_process_url(), $request_array);

    }



    /**

     * After getting back from Buckaroo, this method is called.

     *

     * @return Merchant_response

     */

    public function purchase_return()

    {

        if (!$this->CI->input->post('brq_signature'))

        {

            return new Merchant_response(Merchant_response::FAILED, lang('merchant_invalid_response'));

        }



        // Match incoming key

        if ($this->_calculate_digital_signature($_POST) != $this->CI->input->post('brq_signature'))

        {

            return new Merchant_response(Merchant_response::FAILED, lang('merchant_invalid_response'));

        }



        switch ( (int) $this->CI->input->post('brq_statuscode') )

        {

            // Success

            case self::BUCKAROO_STATUSCODE_PAYMENT_SUCCESS:

                return new Merchant_response(Merchant_response::COMPLETE);

                break;



            // Waiting for action, payment on hold

            case self::BUCKAROO_STATUSCODE_WAITING_FOR_USER_INPUT:

            case self::BUCKAROO_STATUSCODE_WAITING_FOR_PROCESSOR:

            case self::BUCKAROO_STATUSCODE_WAITING_ON_CONSUMER_ACTION:

            case self::BUCKAROO_STATUSCODE_PAYMENT_ON_HOLD:

                return new Merchant_response(Merchant_response::FAILED, lang('merchant_payment_failed'));

                break;



            // Cancelled

            case self::BUCKAROO_STATUSCODE_CANCELLED_BY_CONSUMER:

            case self::BUCKAROO_STATUSCODE_CANCELLED_BY_MERCHANT:

                return new Merchant_response(Merchant_response::FAILED, lang('merchant_payment_failed'));

                break;



            // Failures, errors, rejection

            case self::BUCKAROO_STATUSCODE_PAYMENT_FAILURE:

            case self::BUCKAROO_STATUSCODE_VALIDATION_ERROR:

            case self::BUCKAROO_STATUSCODE_TECHNICAL_ERROR:

            case self::BUCKAROO_STATUSCODE_PAYMENT_REJECTED:

                return new Merchant_response(Merchant_response::FAILED, lang('merchant_payment_failed'));

                break;

        }



        return new Merchant_response(Merchant_response::FAILED, lang('merchant_payment_failed'));

    }



    /**

     * Builds array for use in POST to Buckaroo process URL

     *

     * @return array

     */

    private function _build_purchase()

    {

        $request                      = array();



        /**

         * @desc The unique key of the website for which the payment is placed.

         * @required true

         */

        $request['Brq_websitekey']    = $this->setting('website_key');



        /**

         * @desc The amount to pay in the format 12.34 (always use a dot as a decimal separator)

         * @required true

         */

        $request['Brq_amount']        = $this->amount_dollars();



        /**

         * @desc The currency code (e.g. EUR, USD, GBP). Make sure the specified payment method supports the specified currency.

         * @required true

         */

        $request['Brq_currency']      = $this->currency();



        /**

         * @desc The unique invoice number that identifies the payment. This is a free text field of max. 255 characters.

         * @required true

         */

        $request['Brq_invoicenumber'] = $this->param('transaction_id');



        /**

         * @desc A description of the payment to aid the consumer.

         * @required false

         */

        $request['Brq_description'] = '';



        /**

         * @desc ISO culture code that specifies the language and/or country of residence of the consumer. Examples: en-US, en GB, de-DE, EN or DE.

         * The language part of the culture code is used to apply language localization to the gateway.

         * Currently the following languages are supported: NL, EN, DE. When the culture parameter is not supplied, the default culture nl-NL is used.

         * @required false

         */

        $request['Brq_culture'] = '';



        /**

         * @desc The return URL where the consumer is redirected after payment.

         * If not supplied, the value specified in the Payment Plaza is used.

         * @required false

         */

        $request['Brq_return'] = $this->param('return_url');



        /**

         * @desc The return URL used when the consumer cancels the payment. Fallback is the value in brq_return

         * @required false

         */

        $request['Brq_returncancel'] = '';



        /**

         * @desc The return URL used when the request results in an error. Fallback is the value in brq_return

         * @required false

         */

        $request['Brq_returnerror']  = '';



        /**

         * @desc The return URL used when the payment is rejected by the processor. Fallback is the value in brq_return.

         * @required false

         */

        $request['Brq_returnreject'] = '';



        /**

         * @desc A comma separated list of service codes.

         * If no specific service is passed in the field Brq_payment_method, all available services are displayed to a

         * customer. Use this to specify which services should be shown. (Only services with an active subscription are shown)

         * @required false

         */

        $request['Brq_requestedservices'] = '';



        $request['Brq_signature'] = $this->_calculate_digital_signature($request);



        return $request;

    }



    /**

     * Calculate the Digital Signature.

     * Documentation used: Implementation Manual Buckaroo Payment Engine 3.0 (page 10, heading 6)

     *

     * @param   array   $origArray

     * @return  string  $signature

     */

    private function _calculate_digital_signature($origArray)

    {

        unset($origArray['brq_signature'], $origArray['Brq_signature']);



        $sortableArray = $this->_buckaroo_sort($origArray);



        // turn into string and add the secret key to the end

        $signatureString = '';

        foreach ($sortableArray as $key => $value)

        {

            $signatureString .= $key . '=' . urldecode($value);

        }

        $signatureString .= $this->setting('secret_key');



        // return the SHA1 encoded string for comparison

        $signature = sha1($signatureString);



        return $signature;

    }



    /**

     * Obtained from the Buckaroo documentation.

     *

     * @param   array $array

     * @return  array

     */

    private function _buckaroo_sort($array)

    {

        $arrayToSort = array();

        $origArray   = array();



        foreach ($array as $key => $value)

        {

            $arrayToSort[strtolower($key)] = $value;



            // stores the original value in an array

            $origArray[strtolower($key)] = $key;

        }



        ksort($arrayToSort);



        $sortedArray = array();

        foreach ($arrayToSort as $key => $value)

        {

            // switch the lowercase keys back to their originals

            $key               = $origArray[$key];

            $sortedArray[$key] = $value;

        }



        return $sortedArray;

    }



    /**

     * Finds out the right URL based on the current test mode.

     *

     * @return string

     */

    protected function _process_url()

    {

        return $this->setting('test_mode') ? self::PROCESS_URL_TEST : self::PROCESS_URL;

    }

}



/* End of file ./libraries/merchant/drivers/merchant_buckaroo.php */