<?php
/* -----------------------------------------------------------------------------------------
   $Id: eps2.php,v 1.0 2010/09/11 17:25:00 ertl Exp $

   XT-Commerce - community made shopping
   http://www.xt-commerce.com

   Copyright (c) 2003 XT-Commerce
   -----------------------------------------------------------------------------------------
   Third Party contributions:
   EPS2 v1.0                       Author:   Ludwig Ertl  <ludwig.ertl@softwerker.at>
                                   Company:  SoftWerker Datenservice GmbH
                                   WWW:      http://www.softwerker.at/

   Released under the GNU General Public License
   ---------------------------------------------------------------------------------------*/

  class eps2 {
    var $code, $title, $description, $enabled, $email_footer;
    var $epsLanguages, $defLang, $banks;

// class constructor
    function eps2() {
      global $order;

      $this->code = 'eps2';
      $this->title = MODULE_PAYMENT_EPS2_TEXT_TITLE;
      $this->description = MODULE_PAYMENT_EPS2_TEXT_DESCRIPTION;
      $this->enabled = ((MODULE_PAYMENT_EPS2_STATUS == 'True') ? true : false);
      $this->email_footer = MODULE_PAYMENT_EPS2_TEXT_EMAIL_FOOTER;
      $this->sort_order = MODULE_PAYMENT_EPS2_SORT_ORDER; 
  
      if (is_object($order)) $this->update_status();

      // Now define the logins for the various banking servers available
      $UseTestSystem = (MODULE_PAYMENT_EPS2_TESTSYSTEM == 'True');
      $this->supplogins = array ('EPSSO');
      foreach ($this->supplogins as $login)
      {
        $loginconst=strtoupper($login);
        if (defined('MODULE_PAYMENT_EPS2_'.$loginconst.'_USERID') && constant('MODULE_PAYMENT_EPS2_'.$loginconst.'_USERID') &&
            defined('MODULE_PAYMENT_EPS2_'.$loginconst.'_PWD') && constant('MODULE_PAYMENT_EPS2_'.$loginconst.'_PWD'))
        {
          $logins[$login] = array (
            'enabled' => true, 
            'sapPopRequestor'              => constant('MODULE_PAYMENT_EPS2_'.$loginconst.'_USERID'),
            'HaendlerPIN'                  => constant('MODULE_PAYMENT_EPS2_'.$loginconst.'_PWD'),
            'BfiBicIdentifier'             => constant('MODULE_PAYMENT_EPS2_'.$loginconst.'_BIC'),
            'BeneficiaryAccountIdentifier' => constant('MODULE_PAYMENT_EPS2_'.$loginconst.'_IBAN')
          );
        }
      }
/*
 * Zur Auswahl stehende Banken
 */
$banks=array(
    "EPSSO"				// Name der Bank
    => array (
	"name"				=> "EPS Scheme operator",
	"account"			=> $logins['EPSSO'],
	"Login"				=> $UseTestSystem?"https://routing.eps.or.at/appl/epsSO-test/transinit/eps/v2_4":
					   "https://routing.eps.or.at/appl/epsSO/transinit/eps/v2_4"
    )
);
      // ------------------------- bankurls.inc.php ---------------------------

      $this->banks = $banks;

      // Setup text strings for our banks for the config
      foreach ($this->supplogins as $bank)
      {
	$dat=$banks[$bank];
        $bank=strtoupper($bank);
        if (!$dat['name']) $dat['name']=$bank;
        define ("MODULE_PAYMENT_EPS2_".$bank."_USERID_TITLE", $dat['name']." ".MODULE_PAYMENT_EPS2_USERID_TITLE);
        define ("MODULE_PAYMENT_EPS2_".$bank."_PWD_TITLE", $dat['name']." ".MODULE_PAYMENT_EPS2_PWD_TITLE);
        define ("MODULE_PAYMENT_EPS2_".$bank."_IBAN_TITLE", $dat['name']." ".MODULE_PAYMENT_EPS2_IBAN_TITLE);
        define ("MODULE_PAYMENT_EPS2_".$bank."_BIC_TITLE", $dat['name']." ".MODULE_PAYMENT_EPS2_BIC_TITLE);
	define ("MODULE_PAYMENT_EPS2_".$bank."_USERID_DESC", MODULE_PAYMENT_EPS2_USERID_DESC);
	define ("MODULE_PAYMENT_EPS2_".$bank."_PWD_DESC", MODULE_PAYMENT_EPS2_PWD_DESC);
	define ("MODULE_PAYMENT_EPS2_".$bank."_IBAN_DESC", MODULE_PAYMENT_EPS2_IBAN_DESC);
	define ("MODULE_PAYMENT_EPS2_".$bank."_BIC_DESC", MODULE_PAYMENT_EPS2_BIC_DESC);
      }
    }

////
// Status update
    function update_status() {
      global $order;

      // EPS only works for EUR 
      if ($order->info['currency'] != "EUR") $this->enabled = false;
      else if (((int) MODULE_PAYMENT_EPS2_ZONE > 0))
      {
	$this->enabled = false;
	$check_query = xtc_db_query("select zone_id from ".TABLE_ZONES_TO_GEO_ZONES." where geo_zone_id = '".MODULE_PAYMENT_IEB_ZONE."' and zone_country_id = '".$order->billing['country']['id']."' order by zone_id");
	while ($check = xtc_db_fetch_array($check_query))
        {
          if ($check['zone_id'] < 1)
          {
            $this->enabled = true;
            break;
          }
          elseif ($check['zone_id'] == $order->billing['zone_id'])
          {
            $this->enabled = true;
            break;
          }
	}
      } 
    }

// class methods
    function javascript_validation() {
      return false;
    }

    function selection() {
      return array('id' => $this->code,
                   'module' => $this->title);
    }

    function EPSHeader()
    {
      return "<?xml version=\"1.0\" encoding=\"UTF-8\"  standalone=\"yes\"?>".
        "<epsp:EpsProtocolDetails ".
        "xmlns:epsp=\"http://www.stuzza.at/namespaces/eps/protocol/2011/11\" ".
        "xmlns:atrul=\"http://www.stuzza.at/namespaces/eps/austrianrules/2011/11\" ".
        "xmlns:epi=\"http://www.stuzza.at/namespaces/eps/epi/2011/11\" ".
        "xmlns:eps=\"http://www.stuzza.at/namespaces/eps/payment/2011/11\" ".
        "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ".
        "xsi:schemaLocation=\"http://www.stuzza.at/namespaces/eps/protocol/2011/11 ".
        "http://www.eps.or.at/eps/protocol/20111111/EPSProtocol-V24.xsd\" SessionLanguage=\"DE\">";
    }

    function pre_confirmation_check() {
      global $smarty, $order;

      // Get a new transaction-ID
      do {
        $this->transaction_id = xtc_create_random_value(12, "digits");
        $result = xtc_db_query("SELECT eps2_TRID FROM payment_eps2 WHERE eps2_TRID = '".$this->transaction_id."'");
      } while (mysql_num_rows($result));

      // Now generate the XML-Stream to request information from the server.
      // After we got a valid response, we should have the redirect URL and can proceed with the request
	// -- Setup
	$sapUgawwhg = $order->info['currency'];
	$ChargeCode = 'SHA';  // ChargeCode SHAred
	$netpay_errorcode = '000';
        $banks = $this->banks;
	$bank = 'EPSSO';
        $ReferenceIdentifier = 'NOTUSED';
        $sapUvwzweck = MODULE_PAYMENT_EPS2_ORDER_TEXT . strftime(DATE_FORMAT_SHORT);
        $RemittanceIdentifier = sprintf("%012u%s", $_SESSION['customer_id'], $sapUvwzweck);
        $TransactionOkUrl = xtc_href_link(FILENAME_CHECKOUT_PROCESS, "trid=".$this->transaction_id.'&XTCsid=123123');
        $TransactionNokUrl = xtc_href_link(FILENAME_CHECKOUT_PAYMENT, "payment_error=".$this->code);
        $BeneficiaryNameAddressText = STORE_OWNER;
        $InstructedAmount = $order->info['total'];
        $confirmationurl = HTTP_SERVER . DIR_WS_CATALOG . 'backref2.php?trid='.$this->transaction_id;

    $TransactionOkUrl = str_replace('&', '&amp;', $TransactionOkUrl);
    $TransactionNokUrl = str_replace('&', '&amp;', $TransactionNokUrl);

	// Validation
        if (!$banks[$bank]['account']['BfiBicIdentifier']) 
          xtc_redirect(xtc_href_link(FILENAME_CHECKOUT_PAYMENT, 'payment_error='.$this->code.'&error='.urlencode(MODULE_PAYMENT_EPS2_TEXT_ERROR_NOBIC)));
        if (!$banks[$bank]['account']['BeneficiaryAccountIdentifier']) 
          xtc_redirect(xtc_href_link(FILENAME_CHECKOUT_PAYMENT, 'payment_error='.$this->code.'&error='.urlencode(MODULE_PAYMENT_EPS2_TEXT_ERROR_NOIBAN)));

	// XML-Stream
        $xmldata.=$this->EPSHeader();
	$xmldata.="<epsp:TransferInitiatorDetails><eps:PaymentInitiatorDetails><epi:EpiDetails><epi:IdentificationDetails>";
	$xmldata.="<epi:Date>".date("Y-m-d")."</epi:Date><epi:ReferenceIdentifier>$ReferenceIdentifier</epi:ReferenceIdentifier>";
	$xmldata.="</epi:IdentificationDetails><epi:PartyDetails><epi:BfiPartyDetails><epi:BfiBicIdentifier>".$banks[$bank]['account']['BfiBicIdentifier']."</epi:BfiBicIdentifier></epi:BfiPartyDetails><epi:BeneficiaryPartyDetails>";
	$xmldata.="<epi:BeneficiaryNameAddressText>$BeneficiaryNameAddressText</epi:BeneficiaryNameAddressText>";
	$xmldata.="<epi:BeneficiaryAccountIdentifier>".$banks[$bank]['account']['BeneficiaryAccountIdentifier']."</epi:BeneficiaryAccountIdentifier></epi:BeneficiaryPartyDetails></epi:PartyDetails>";
	$xmldata.="<epi:PaymentInstructionDetails>";
	$xmldata.="<epi:RemittanceIdentifier>$RemittanceIdentifier</epi:RemittanceIdentifier><epi:InstructedAmount AmountCurrencyIdentifier=\"$sapUgawwhg\">$InstructedAmount</epi:InstructedAmount>";
	$xmldata.="<epi:ChargeCode>$ChargeCode</epi:ChargeCode>";
	$xmldata.="</epi:PaymentInstructionDetails></epi:EpiDetails>";
	$xmldata.="</eps:PaymentInitiatorDetails><epsp:TransferMsgDetails><epsp:ConfirmationUrl>$confirmationurl</epsp:ConfirmationUrl>";
	$xmldata.="<epsp:TransactionOkUrl".$targetwnd.">$TransactionOkUrl</epsp:TransactionOkUrl>";
	$xmldata.="<epsp:TransactionNokUrl".$targetwnd.">$TransactionNokUrl</epsp:TransactionNokUrl>";
	$xmldata.="</epsp:TransferMsgDetails>";
        $xmldata.="<epsp:WebshopDetails>";
        foreach ($order->products as $prod)
          $xmldata.="<epsp:WebshopArticle ArticleName=\"".$prod['name']."\" ArticleCount=\"".$prod['qty']."\" ArticlePrice=\"".$prod['price']."\"/>";
        $xmldata.="</epsp:WebshopDetails>";
	$xmldata.="<epsp:AuthenticationDetails><epsp:UserId>".$banks[$bank]['account']['sapPopRequestor']."</epsp:UserId>";
	$hash=$banks[$bank]['account']['HaendlerPIN'].date("Y-m-d").$ReferenceIdentifier.$banks[$bank]['account']['BeneficiaryAccountIdentifier'].
	    $RemittanceIdentifier.$InstructedAmount.$sapUgawwhg.$banks[$bank]['account']['sapPopRequestor'];
	$hash=utf8_encode($hash);
	$xmldata.="<epsp:MD5Fingerprint>".md5($hash)."</epsp:MD5Fingerprint>";
	$xmldata.="</epsp:AuthenticationDetails></epsp:TransferInitiatorDetails></epsp:EpsProtocolDetails>";

//die ($xmldata);
	// POST with CURL
	$ch = curl_init();
	curl_setopt($ch, CURLOPT_URL,$banks[$bank]['Login']);
	curl_setopt($ch, CURLOPT_POST,1);
	curl_setopt($ch, CURLOPT_POSTFIELDS, utf8_encode($xmldata));
	curl_setopt($ch, CURLOPT_TIMEOUT, 60);
	curl_setopt($ch, CURLOPT_HEADER,0);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
	curl_setopt($ch, CURLOPT_HTTPHEADER, Array("Content-Type: text/xml"));
	$result=curl_exec ($ch);
	curl_close ($ch);


	// Parse requlting XML stream
	$currentTag="";
	$xml_parser = xml_parser_create();
        xml_set_object ( $xml_parser, $this );
        xml_set_element_handler($xml_parser, "DoOrder_startElement", "DoOrder_endElement"); // callback fkt. setzen
        xml_set_character_data_handler($xml_parser, "DoOrder_characterData");
	if (!xml_parse($xml_parser, $result)) 
        {
            xtc_redirect(xtc_href_link(FILENAME_CHECKOUT_PAYMENT, 'payment_error='.$this->code.'&error='.urlencode(
              sprintf("XML error: %s in line %d, col %d\n%s",xml_error_string(xml_get_error_code($xml_parser)),xml_get_current_line_number($xml_parser),
                xml_get_current_column_number($xml_parser), $result))));
	    xml_parser_free($xml_parser);
            return false;
        }
	xml_parser_free($xml_parser);

      // Now that we hopefully have to correct URL to redirect, we are done
      if ($this->xml_result['ERRORCODE'] > 0)
      {	
	/*
	$fp = fopen("/tmp/stream.txt", 'w');
	fwrite ($fp, $xmldata."\n");
	fwrite ($fp, $result."\n");
	fclose($fp);
	*/
            xtc_redirect(xtc_href_link(FILENAME_CHECKOUT_PAYMENT, 'payment_error='.$this->code.'&error='.urlencode($this->xml_result['ERRORMSG'])));
      }
      $this->form_action_url = $this->xml_result['CLIENTREDIRECTURL'];

      return false;
    }

    function process_button() {
      global $smarty;

      // EPS SO unfortunately doesn't like a POST, so we do a hack with javascript :(
      // We could also POST to FILENAME_CHECKOUT_PROCESS with a $_REQUEST parameter and then redirect, but this way it should work too.
      $smarty->assign('CHECKOUT_FORM', xtc_draw_form('checkout_confirmation', '#', 'post', "onsubmit=\"document.location.href='".$this->form_action_url."'; return false;\""));
      return false;
    }

    function confirmation() {
      return false;
    }

    function before_process() {
      global $order, $_GET;

      // Now check if the EPS-server returned OK -> If yes, order status will be changed to 'Processing'
      // In case of a NOK, you shouldn't land here anyways, but better check it, as otherwise users might have
      // a chance to cheat by manuelly calling the sapPopOkUrl
      $this->transaction_id = $_GET["trid"];
      $result = xtc_db_query("SELECT eps2_RETURNSTATUS FROM payment_eps2 WHERE eps2_TRID = '{$this->transaction_id}'");
      list($sapPopStsReturnStatus) = mysql_fetch_row($result);
      $sapPopStsReturnStatus = strtoupper($sapPopStsReturnStatus);
      if ($sapPopStsReturnStatus=="OK" || $sapPopStsReturnStatus=="VOK") $order->info['order_status'] = MODULE_PAYMENT_EPS2_ORDER_STATUS_ID>0?MODULE_PAYMENT_EPS2_ORDER_STATUS_ID:2;
      else xtc_redirect(xtc_href_link(FILENAME_CHECKOUT_PAYMENT, "payment_error=".$this->code."&error=".
		($sapPopStsReturnStatus?$sapPopStsReturnStatus:MODULE_PAYMENT_EPS2_TEXT_ERROR_NO_REPLY)));
    }

    function after_process() {
     global $insert_id;

     // Insert order-id for this order so that you can trace it later
     $result = xtc_db_query("UPDATE payment_eps2 SET eps2_ORDERID = $insert_id WHERE eps2_TRID = '{$this->transaction_id}'");
    }

    function get_error() {
      global $_GET;

      // Altough this behaviour is EPS2 - specific, the Volksbank for instance implemented this useful behaviour in EPS2 too
      if ($_GET['epserrorcode'])
      {
       switch (strtoupper($_GET['epserrorcode']))
         {
          case "ERROR1": $msg=MODULE_PAYMENT_EPS2_TEXT_ERROR1; break;
          case "ERROR2": $msg=MODULE_PAYMENT_EPS2_TEXT_ERROR2; break;
          case "ERROR3":
          case "ERROR4":
          case "ERROR5": $msg=MODULE_PAYMENT_EPS2_TEXT_ERROR3; break;
          default: $msg=MODULE_PAYMENT_EPS2_TEXT_ERROR; break;
        }
     } else $msg=$_REQUEST['error'];

      $error = array('title' => MODULE_PAYMENT_EPS2_TEXT_ERROR,
                     'error' => $msg);

      return $error;
    }

    // Installation check
    function check() {
      if (!isset($this->_check)) {
        $check_query = xtc_db_query("select configuration_value from " . TABLE_CONFIGURATION . " where configuration_key = 'MODULE_PAYMENT_EPS2_STATUS'");
        $this->_check = xtc_db_num_rows($check_query);
      }
      return $this->_check;
    }

    // Installation - write initial configuration tables and create our tracing-table
    function install() {
      xtc_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_key, configuration_value,  configuration_group_id, sort_order, set_function, date_added) values ('MODULE_PAYMENT_EPS2_STATUS', 'True',  '6', '0', 'xtc_cfg_select_option(array(\'True\', \'False\'), ', now())");
      xtc_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_key, configuration_value,  configuration_group_id, sort_order, date_added) values ('MODULE_PAYMENT_EPS2_ALLOWED', '', '6', '0', now())");
      xtc_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_key, configuration_value,  configuration_group_id, sort_order, set_function, date_added) values ('MODULE_PAYMENT_EPS2_TESTSYSTEM', 'False',  '6', '2', 'xtc_cfg_select_option(array(\'True\', \'False\'), ', now())");
      xtc_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_key, configuration_value,  configuration_group_id, sort_order, set_function, use_function, date_added) values ('MODULE_PAYMENT_EPS2_ORDER_STATUS_ID', '0',  '6', '3', 'xtc_cfg_pull_down_order_statuses(', 'xtc_get_order_status_name', now())");
      xtc_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_key, configuration_value,  configuration_group_id, sort_order, use_function, set_function, date_added) values ('MODULE_PAYMENT_EPS2_ZONE', '0',  '6', '4', 'xtc_get_zone_class_title', 'xtc_cfg_pull_down_zone_classes(', now())"); 
      xtc_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_key, configuration_value,  configuration_group_id, sort_order, date_added) values ('MODULE_PAYMENT_EPS2_SORT_ORDER', '0',  '6', '5', now())"); 
      $cnt=6;
      foreach ($this->supplogins as $bank)
      {
        $bank=strtoupper($bank);
        // Migration EPS1 -> EPS2, if EPS1 exists
        $result = xtc_db_query("SELECT configuration_value FROM ".TABLE_CONFIGURATION." WHERE configuration_key='MODULE_PAYMENT_EPS1_".$bank."_USERID'");
        list($eps1val) = mysql_fetch_row($result);
        xtc_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_key, configuration_value,  configuration_group_id, sort_order, date_added) values ('MODULE_PAYMENT_EPS2_".$bank."_USERID', '".$eps1val."', '6', '".$cnt++."', now())");
        $result = xtc_db_query("SELECT configuration_value FROM ".TABLE_CONFIGURATION." WHERE configuration_key='MODULE_PAYMENT_EPS1_".$bank."_PWD'");
        list($eps1val) = mysql_fetch_row($result);
        xtc_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_key, configuration_value,  configuration_group_id, sort_order, date_added) values ('MODULE_PAYMENT_EPS2_".$bank."_PWD', '".$eps1val."',  '6', '".$cnt++."', now())");
        xtc_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_key, configuration_value,  configuration_group_id, sort_order, date_added) values ('MODULE_PAYMENT_EPS2_".$bank."_IBAN', '',  '6', '".$cnt++."', now())");
        xtc_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_key, configuration_value,  configuration_group_id, sort_order, date_added) values ('MODULE_PAYMENT_EPS2_".$bank."_BIC', '',  '6', '".$cnt++."', now())");
      }
      xtc_db_query("CREATE TABLE IF NOT EXISTS payment_eps2 (eps2_TRID varchar(255) NOT NULL default '', eps2_RETURNSTATUS varchar(255) NOT NULL default '0', eps2_DATE datetime NOT NULL default '0000-00-00 00:00:00', eps2_ORDERID int(11) unsigned NOT NULL default '0', PRIMARY KEY  (eps2_TRID));");
    }

    // Uninstall - Delete configuration from database
    function remove() {
      xtc_db_query($qry = "delete from " . TABLE_CONFIGURATION . " where configuration_key in ('" . implode("', '", array_merge($this->keys(),array("MODULE_PAYMENT_EPS2_ALLOWED"))) . "')");
    }

    // Our configuration constants
    function keys() {
      $keys=array('MODULE_PAYMENT_EPS2_STATUS', 'MODULE_PAYMENT_EPS2_TESTSYSTEM', 'MODULE_PAYMENT_EPS2_ORDER_STATUS_ID', 'MODULE_PAYMENT_EPS2_ZONE', 'MODULE_PAYMENT_EPS2_SORT_ORDER');
      foreach ($this->supplogins as $bank)
      {
        $bank=strtoupper($bank);
        array_push($keys, "MODULE_PAYMENT_EPS2_".$bank."_USERID");
        array_push($keys, "MODULE_PAYMENT_EPS2_".$bank."_PWD");
        array_push($keys, "MODULE_PAYMENT_EPS2_".$bank."_IBAN");
        array_push($keys, "MODULE_PAYMENT_EPS2_".$bank."_BIC");
      }
      return $keys;
    }

// Static
//

    // Parse the predefinied array to be 'module install' friendly
    // as it is used for select in the module's install() function
    function show_array($aArray, $bKeys=false) {
      $aFormatted = "array(";
      foreach ($aArray as $key=>$sVal) {
        $aFormatted .= ($bKeys?"\'$key\', ":"\'$sVal\', ");
      }
      $aFormatted = substr($aFormatted, 0, strlen($aFormatted)-2);
      return $aFormatted;
    }

    function DoOrder_startElement($parser, $name, $attrs) {
	$this->currentTag=$name;
    }

    function DoOrder_endElement($parser, $name) {
	unset($this->currentTag);
    }

    function DoOrder_characterData($parser, $data) {
	list($prefix, $tag)=split(":", $this->currentTag, 2);
	if (!$tag) $tag=$this->currentTag;
        $this->xml_result[$tag].=$data;
    }

  }
?>
