News:

You may pay someone to create your store, or you visit our seminar and become a professional yourself with the silver certification

Main Menu

ProtX

Started by Rob, September 09, 2004, 18:44:00 PM

Previous topic - Next topic

Rob

I'd like to see a PSP for protx.

http://www.protx.com

I'm currently looking into PSP's and protX seems to be the best (i.e cheapest!) for low volume shops, like mine.

I'm happy to help develop one.  i just need to look into it a bit more.

Thanks.

Danny Locksmith

According to Protx
QuoteVSP Form is the ideal system for your website. It operates in a similar manner to the other Payment Service Providers, sending transaction registration information in hidden HTML fields through the customers browser

This means you can adapt the Paypal method....
1) New payment method
2) Put the appropriate code into \"Payment Extra Info\"
3) Write a script to deal with the response from Protx

This is not a detailed explanation, I have not read the details at protx and I am still learning myself.
Protx encrypt the details before they are submitted, This may cause extra difficulties.

It took me a week or so to get my Worldpay integration working.
And as a result I am far more aware of how MAMBO and PHP-shop works.

mitch_a

Any joy with the Protx intergration ?

Grateful if you could update re progress / steps taken etc.

Thanks

anij

I too am interested in a protx module.
I have used the one in OScommerce & it wirks fine.
You can easily look @ the code for that.

chris

dlocksmith wrote:

This means you can adapt the Paypal method....
1) New payment method
2) Put the appropriate code into \"Payment Extra Info\"
3) Write a script to deal with the response from Protx

Hi dlocksmith

Have you had a chance to look at the Protx issue in more detail?

I would be very grateful for some more detail on your method of converting the Paypal to Protx.

Thank you for any help you can give.......and Merry Xmas!!!

Kevin Igoe

Hi Folks

it seems ProtX is a pretty popular payment gateway. I'm also trying to integrate ProtX with my site, but all I've got so far is their VSP form. I'm trying to extact the necessary info out of that, as I believe that the process they use is similar to that used by authorize.net (who I can't use without a US$ account).

If anybody makes any more progress on this, or has any ideas, I'd appreciate it if you could get in touch. If you're interested in the PHPFormKit that they have, I have a cope and have it installed on http://www.tnc.k1z.com/PHPFormKit if you want to check it out.

Hope someone has more luck than I've had.
Ciao for niao

anbujawahar R

:(  hello anyone got it right  on protx integration on mambo phpshop?  i have to add this to our site asap. pls reply to me.

jema

Did this get done? I have just looked at the kit instructions and frankly it does not look very hard to do.

chris

Hi

Another vote here for Protx integration....I won't hold my breath though, I've been waiting for nearly a year so far for some kind person to develop it ;)

Would be nice though as Protx are really cheap and reliable.

xtencilate

Same here, would rely love some help with Protx.

Maxbuyer

Another vote for Protx. Please consider adding this.

Xirium

I have mambo-phpShop and ProTX integration working on http://www.pogoboxes.com/. If anyone would like help with this matter then its quickest to contact me by telephone on +44 7867 774360.

Quote from: Danny LocksmithProtx encrypt the details before they are submitted, This may cause extra difficulties.

Y, that is a pain. Your shared secret, nonce, or whatever you want to call it, is not used to to generate a hash or checksum, like on most other systems. Instead, the majority of the fields are encoded within an encrypted payload. This means you get minimal feedback if you're using the wrong secret value. This wouldn't be too bad except ProTX insist that you demonstrate competence with ProTX's admin interface before you go live. This requires changing your configuration at least twice.

Persevere because it can be done.

nickweavers

#12
Hi Xirium, your ps_protx_cpi worked well for me last night. The bit that needs a little more work is the feedback of data about the transaction from protx.

I was trying to code up a page in the com_phpshop/html folder I called checkout.protx_cpi_result.php that will be the URL used by ProTx for both the SUCCESS and FAILURE cases. Since ProTx send this URL a crypt string that contains all you need to know about the outcome of the transaction, you can handle all of the different cases in this php file. Most importantly what I would like to do is take the authorisation code they send back for a successful transaction and store it in the database against the order.

Oh yeah, and because checkout.protx_cpi_result.php page is under the com_phpshop umbrella the Itemid for the URI will be the same as it is for the main pages and you don't have to create any new content pages up front as you do with your existing scheme  ;)

The message codes that are handed back are OK, NOTAUTHED, ERROR and ABORT. 

Thanks for the great work you have done and for the kind and generous support you gave a fellow mambo_phpshop'er  :)

 

nickweavers

With the help of Xirium here is what you need to get Protx working in mambo-phpshop. I'll post the solution in parts as it exceeds the 2000 chars max allowed per post.

You need to place this php into a file called ps_protx_cpi.php under your httpdocs/CMS/administrator/components/com_phpshop/classes/payment directory:


<?php
defined
'_VALID_MOS' ) or die( 'Direct Access to this location is not allowed.' );
/**
* @version $Id: ps_protx_cpi.php,v 1.0 2005/07/26 17:00:00 gandalf Exp $
* @package mambo-phpShop
* @subpackage Payment
* @copyright (C) 2004-2005 Soeren Eberhardt
*
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
* mambo-phpShop is Free Software.
* mambo-phpShop comes with absolute no warranty.
*
* www.mambo-phpshop.net
*
*/

class ps_protx_cpi {

    var 
$classname "ps_protx_cpi";
    var 
$payment_code "PROTXCPI";

    
/**
    * Show all configuration parameters for this payment method
    * @returns boolean False when the Payment method has no configration
    */
    
function show_configuration() {
        global 
$PHPSHOP_LANG;
        
        
/** Read current Configuration ***/
        
require_once(CLASSPATH ."payment/".$this->classname.".cfg.php");
        
?>

        <strong>ProtX Configuration</strong>
        <table>
          <tr><td><input type="text" name="PROTX_CPI_STORE_ID" class="inputbox" value="<? echo PROTX_CPI_STORE_ID ?>" Size=32 /></td>
  <td>The name of your store. Usually the same as your organisation.</td></tr>
          <tr><td><input type="text" name="PROTX_CPI_SECRET" class="inputbox" value="<? echo PROTX_CPI_SECRET ?>" Size=32 /></td>
  <td>The "Encryption Password" you get from ProTX.</td></tr>
  <tr><td><input type="text" name="PROTX_CPI_ApplyAVSCV2" class="inputbox" value="<? echo PROTX_CPI_ApplyAVSCV2 ?>" Size=32 /></td>
  <td>Activate the ProTX "Address and Security Code Verification (AVSCV2) Service". 0 for NO, 1 for YES</td></tr>
  <tr><td><input type="text" name="PROTX_CPI_Apply3DSecure" class="inputbox" value="<? echo PROTX_CPI_Apply3DSecure ?>" Size=32 /></td>
  <td>Activate the ProTX "3DSecure Service". 0 for NO, 1 for YES</td></tr>  
          <tr><td><input type="text" name="PROTX_CPI_REMOTE_HOST" class="inputbox" value="<? echo PROTX_CPI_REMOTE_HOST ?>" Size=32 /></td>
  <td>The hostname of the secure URL for the payment gateway. Given as "API Post URL" not "CPI Post URL". Ends with ".com".</td>
  </tr>
          <tr><td><input type="text" name="PROTX_CPI_REMOTE_PATH" class="inputbox" value="<? echo PROTX_CPI_REMOTE_PATH ?>" Size=32 /></td>
  <td>The path of the secure URL for the payment gateway. Given as "API Post URL" not "CPI Post URL". Everything after ".com" including a slash ("/").</td></tr>
          <tr><td><input type="text" name="PROTX_CPI_SUCCESS_URL" class="inputbox" value="<? echo PROTX_CPI_SUCCESS_URL ?>" Size=32 /></td>
  <td>The success URL. This should be 'http://www.yourdomain/CMS/index.php?&option=com_phpshop&page=checkout.protx_cpi_result' </td></tr>
          <tr><td><input type="text" name="PROTX_CPI_FAIL_URL" class="inputbox" value="<? echo PROTX_CPI_FAIL_URL ?>" Size=32 /></td>
  <td>The failure URL. This should be 'http://www.yourdomain/CMS/index.php?&option=com_phpshop&page=checkout.protx_cpi_result' </td></tr>
        </table>
        <?php
    
}
    
    function 
has_configuration() {
      
// return false if there's no configuration
      
return true;
    }
   
  
/**
* Returns the "is_writeable" status of the configuration file
* @param void
* @returns boolean True when the configuration file is writeable, false when not
*/
   
function configfile_writeable() {
      return 
is_writeableCLASSPATH."payment/".$this->classname.".cfg.php" );
   }
   
  
/**
* Returns the "is_readable" status of the configuration file
* @param void
* @returns boolean True when the configuration file is writeable, false when not
*/
   
function configfile_readable() {
      return 
is_readableCLASSPATH."payment/".$this->classname.".cfg.php" );
   }
   
  
/**
* Writes the configuration file for this payment method
* @param array An array of objects
* @returns boolean True when writing was successful
*/
   
function write_configuration( &$d ) {
      
      
$my_config_array = array(
        
"PROTX_CPI_STORE_ID" => $d['PROTX_CPI_STORE_ID'],
        
"PROTX_CPI_SECRET" => $d['PROTX_CPI_SECRET'],
        
"PROTX_CPI_ApplyAVSCV2" => $d['PROTX_CPI_ApplyAVSCV2'],
        
"PROTX_CPI_Apply3DSecure" => $d['PROTX_CPI_Apply3DSecure'],
        
"PROTX_CPI_REMOTE_HOST" => $d['PROTX_CPI_REMOTE_HOST'],
        
"PROTX_CPI_REMOTE_PATH" => $d['PROTX_CPI_REMOTE_PATH'],
        
"PROTX_CPI_SUCCESS_URL" => $d['PROTX_CPI_SUCCESS_URL'],
        
"PROTX_CPI_FAIL_URL" => $d['PROTX_CPI_FAIL_URL']
      );
      
$config '<?php\n';
      
$config .= "defined('_VALID_MOS') or die('Direct Access to this location is not allowed.'); \n\n";
      foreach( 
$my_config_array as $key => $value ) {
        
$config .= "define ('$key', '$value');\n";
      }
      
      
$config .= '?>
';
 
      if ($fp = fopen(CLASSPATH ."payment/".$this->classname.".cfg.php", "w")) {
          fputs($fp, $config, strlen($config));
          fclose ($fp);
          return true;
     }
     else
        return false;
   }

// simplexor taken from protx.com php-form-kit.zip:

/*  The SimpleXor encryption algorithm                                                                                **
**  NOTE: This is a placeholder really.  Future releases of VSP Form will use AES or TwoFish.  Proper encryption      **
**      This simple function and the Base64 will deter script kiddies and prevent the "View Source" type tampering    **
**      It won't stop a half decent hacker though, but the most they could do is change the amount field to something **
**      else, so provided the vendor checks the reports and compares amounts, there is no harm done.  It's still      **
**      more secure than the other PSPs who don't both encrypting their forms at all                                  */

function simpleXor($InString, $Key) {
  // Initialise key array
  $KeyList = array();
  // Initialise out variable
  $output = "";
 
  // Convert $Key into array of ASCII values
  for($i = 0; $i < strlen($Key); $i++){
    $KeyList[$i] = ord(substr($Key, $i, 1));
  }

  // Step through string a character at a time
  for($i = 0; $i < strlen($InString); $i++) {
    // Get ASCII code from string, get ASCII code from key (loop through with MOD), XOR the two, get the character from the result
    // % is MOD (modulus), ^ is XOR
    $output.= chr(ord(substr($InString, $i, 1)) ^ ($KeyList[$i % strlen($Key)]));
  }

  // Return the result
  return $output;
}

/* The getToken function.                                                                                         **
** NOTE: A function of convenience that extracts the value from the "name=value&name2=value2..." VSP reply string **
**     Works even if one of the values is a URL containing the & or = signs.                                      */

function getToken($thisString) {

  // List the possible tokens
  $Tokens = array(
    "Status",
    "StatusDetail",
    "VendorTxCode",
    "VPSTxId",
    "TxAuthNo",
    "Amount",
    "AVSCV2",
    "AddressResult",
    "PostCodeResult",
    "CV2Result",
    "GiftAid",
    "3DSecureStatus",
    "CAVV" );

  // Initialise arrays
  $output = array();
  $resultArray = array();
 
  // Get the next token in the sequence
  for ($i = count($Tokens)-1; $i >= 0 ; $i--){
    // Find the position in the string
    $start = strpos($thisString, $Tokens[$i]);
    // If it's present
    if ($start !== false){
      // Record position and token name
      $resultArray[$i]->start = $start;
      $resultArray[$i]->token = $Tokens[$i];
    }
  }
 
  // Sort in order of position
  sort($resultArray);

  // Go through the result array, getting the token values
  for ($i = 0; $i<count($resultArray); $i++){
    // Get the start point of the value
    $valueStart = $resultArray[$i]->start + strlen($resultArray[$i]->token) + 1;
    // Get the length of the value
    if ($i==(count($resultArray)-1)) {
      $output[$resultArray[$i]->token] = substr($thisString, $valueStart);
    } else {
      $valueLength = $resultArray[$i+1]->start - $resultArray[$i]->start - strlen($resultArray[$i]->token) - 2;
      $output[$resultArray[$i]->token] = substr($thisString, $valueStart, $valueLength);
    }     

  }

  // Return the ouput array
  return $output;

}

  /**************************************************************************
  ** name: process_payment()
  ** created by: gandalf
  ** description: process transaction through ProtX
  ** parameters: $order_number, the number of the order, we're processing here
  **             $order_total, the total cost of the order
  **             $d, transaction state
  ** returns: bool, true on successful transaction
  ***************************************************************************/
   function process_payment($order_number, $order_total, &$d) {

global $vendor_mail, $vendor_currency, $PHPSHOP_LANG, $database;

        require_once(CLASSPATH."payment/".$this->classname.".cfg.php");
        $auth = $_SESSION['auth'];

        // Get user billing information
        $dbbt = new ps_DB;
        $qt = "SELECT * FROM #__users WHERE id='".$auth["user_id"]."' AND address_type='BT'";
        $dbbt->query($qt);
        $dbbt->next_record();
        $user_info_id = $dbbt->f("user_info_id");
        if( $user_info_id != $d["ship_to_info_id"]) {
            // Get user billing information
            $dbst =& new ps_DB;
            $qt = "SELECT * FROM #__pshop_user_info WHERE user_info_id='".$d["ship_to_info_id"]."' AND address_type='ST'";
            $dbst->query($qt);
            $dbst->next_record();
        }
        else {
            $dbst = $dbbt;
        }

// system fields
$nl=chr(13).chr(10);
$temp="";
$temp.='VendorTxCode='.$order_number;
$temp.='&';
$temp.='Amount='.number_format($order_total,2,'.','');
$temp.='&';
$temp.='Currency='.$vendor_currency;
$temp.='&';
$temp.='Description=Your Order';
if(PROTX_CPI_SUCCESS_URL!='')
{
$temp.='&';
$temp.='SuccessURL='.PROTX_CPI_SUCCESS_URL;
}
if(PROTX_CPI_FAIL_URL!='')
{
$temp.='&';
$temp.='FailureURL='.PROTX_CPI_FAIL_URL;
}
$temp.='&';
$temp.='CustomerEmail='.substr($dbbt->f('email'),0,50);
$temp.='&';
$temp.='CustomerName='.substr($dbbt->f('first_name').' '.$dbbt->f('last_name'),0,30);
$temp.='&';
$temp.='VendorEmail='.substr($vendor_mail,0,2000);
$temp.='&';
$temp.='DeliveryAddress='.$dbbt->f('address_1').$nl.$dbbt->f('address_2').$nl.$dbbt->f('city').$nl.$dbbt->f('state').$nl.$dbbt->f('country');
$temp.='&';
$temp.='DeliveryPostCode='.substr($dbbt->f('zip'),0,20);
$temp.='&';
$temp.='BillingAddress='.$dbbt->f('address_1').$nl.$dbbt->f('address_2').$nl.$dbbt->f('city').$nl.$dbbt->f('state').$nl.$dbbt->f('country');
$temp.='&';
$temp.='BillingPostCode='.substr($dbbt->f('zip'),0,20);
$temp.='&';
$temp.='ContactNumber='.substr($dbbt->f('phone_1'),0,20);
$temp.='&';
$temp.='ContactFax='.substr($dbbt->f('fax'),0,20);
$temp.='&';
$temp.='AllowGiftAid=0';
$temp.='&';
$temp.='ApplyAVSCV2='.PROTX_CPI_ApplyAVSCV2;
$temp.='&';
$temp.='Apply3DSecure='.PROTX_CPI_Apply3DSecure;
$_SESSION['ProTX0_Post']="https://".PROTX_CPI_REMOTE_HOST.PROTX_CPI_REMOTE_PATH;
$_SESSION['ProTX1_VPSProtocol']='2.22';
$_SESSION['ProTX1_TxType']='PAYMENT';
$_SESSION['ProTX1_Vendor']=PROTX_CPI_STORE_ID;
$_SESSION['ProTX1_Crypt']=base64_encode($this->simpleXor($temp,PROTX_CPI_SECRET));
    return true;
   }
   
}



nickweavers

#14
Then paste this into a file called ps_protx_cpi.cfg.php in the same directory:



<?php
defined
('_VALID_MOS') or die('Direct Access to this location is not allowed.'); 
define ('PROTX_CPI_STORE_ID''yourProtxAccountName'); 
define ('PROTX_CPI_SECRET''stageOneEncryptionKey'); // stage 1
//define ('PROTX_CPI_SECRET', 'stageTwoEncryptionKey'); // stage 2
//define ('PROTX_CPI_SECRET', 'stageThreeEncryptionKey'); // stage 3
define ('PROTX_CPI_REMOTE_HOST''ukvpstest.protx.com'); // stage 1 & 2
//define ('PROTX_CPI_REMOTE_HOST', 'ukvps.protx.com'); // stage 3
define ('PROTX_CPI_REMOTE_PATH','/VSPSimulator/VSPFormGateway.asp'); // stage 1
//define ('PROTX_CPI_REMOTE_PATH', '/vps2Form/submit.asp'); // stage 2
//define ('PROTX_CPI_REMOTE_PATH', '/vps2Form/submit.asp'); // stage 3
define ('PROTX_CPI_ApplyAVSCV2''0'); //set this as desired
define ('PROTX_CPI_Apply3DSecure''0'); //set this as desired
define ('PROTX_CPI_SUCCESS_URL''http://www.yourdomain/CMS/index.php?&option=com_phpshop&page=checkout.protx_cpi_result');
define ('PROTX_CPI_FAIL_URL''http://www.yourdomain/CMS/index.php?&option=com_phpshop&page=checkout.protx_cpi_result');
?>



Replace the strings yourProtxAccountName, stageOneEncryptionKey and yourdomain with the appropriate values for your site and your Protx account.

Next paste the following code into a file called checkout.protx_cpi_result.php in directory httpdocs/CMS/administrator/components/com_phpshop/classes/html


<?php
defined
'_VALID_MOS' ) or die( 'Direct Access to this location is not allowed.' ); 
/*
* @version $Id: checkout.protx_cpi_result.php,v 1.13 2005/08/16 01:19:55 SiteWeavers Exp $
* @package Mambo_4.5.1
* @subpackage mambo-phpShop
* Contains code from PHPShop(tm):
@copyright (C) 2000 - 2004 Edikon Corporation (www.edikon.com)
* Community: www.phpshop.org, forums.phpshop.org
* Conversion to Mambo and the rest:
@copyright (C) 2004 Soeren Eberhardt
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
* mambo-phpShop is Free Software.
* mambo-phpShop comes with absolute no warranty.
*
* www.mambo-phpshop.net
*
* Protx VSPForm returns a buyer to this page at the end of a transaction. The URI must be 
* inspected to see whether the transaction was successful or not. 
* A successful transaction is signalled by an "OK" message. If successful it will also 
* contain an authorisation code which should be stored in the database against the order.
* Unsuccessful message codes are as follows:
* NOTAUTHED
* ERROR
* ABORT 
*/
if ($_GET) {

    
define('_VALID_MOS''1');

    global 
$database$mainframe$mosConfig_absolute_path$mosConfig_live_site$mosConfig_lang;

    
$database = new database$mosConfig_host$mosConfig_user$mosConfig_password$mosConfig_db$mosConfig_dbprefix );

    
// load Mambo Language File
    
if (file_exists$mosConfig_absolute_path'/language/'.$mosConfig_lang.'.php' )){
      require_once( 
$mosConfig_absolute_path'/language/'.$mosConfig_lang.'.php' );
    } else {
      require_once( 
$mosConfig_absolute_path'/language/english.php' );
    }

    
define('PHPSHOPPATH'$mosConfig_absolute_path.'/administrator/components/com_phpshop/');
    require_once(
PHPSHOPPATH."phpshop.cfg.php");

    
//Set up the mailer to infor Warehouse of validated order
    //require_once( $mosConfig_absolute_path . '/includes/phpmailer/class.phpmailer.php');
    //$mail = new mosPHPMailer();
    //$mail->PluginDir = $mosConfig_absolute_path . '/includes/phpmailer/';
    //$mail->SetLanguage("en", $mosConfig_absolute_path . '/includes/phpmailer/language/');

    // load the mambo-phpShop Language File 
    
if (file_existsADMINPATH'languages/'.$mosConfig_lang.'.php' )) {
      require_once( 
ADMINPATH'languages/'.$mosConfig_lang.'.php' );
    } else {
      require_once( 
ADMINPATH'languages/english.php' );
    }
    require_once( 
CLASSPATH'payment/ps_protx_cpi.cfg.php' );
    require_once( 
CLASSPATH'payment/ps_protx_cpi.php' );
    
// Load the mambo-phpShop database class
    
require_once( CLASSPATH'ps_database.php' );
    
// At this point we can access the simpleXOR function again and decode the crypt string
$message_from_protx ps_protx_cpi::simpleXor(base64_decode($_GET['crypt']),PROTX_CPI_SECRET);
$notification ps_protx_cpi::getToken($message_from_protx);
    require_once ( 
CLASSPATH 'ps_order.php' );
$ps_order = new ps_order;
$d['order_number'] = $notification['VendorTxCode'];

// Do it yourself method

$q "SELECT * FROM #__pshop_orders WHERE ".
         
"#__pshop_orders.user_id='".$auth['user_id']."' AND ".
 "#__pshop_orders.order_number='".$d['order_number']."';"
 ;
 
$database->setQuery($q);
    
$order_list $database->loadObjectList();
    if (
$database -> getErrorNum()) {
          echo 
$database -> stderr();
    }

$d['order_id'] = trim($order_list[0]->order_id);
switch ($notification['Status']) {
  case "OK":
    // The OK response is sent when a transaction is successfully authorised. The customer will be redirected 
// to the SuccessURL page (this page) which should store the TxAuthNo field against the transaction details in your database, 
// along with any other details you wish to store, before presenting the customer with successful completion details.
    $d['order_status'] = 'C';  //set the new value for the database field: X for cancelled, C for confirmed
    echo "Thankyou for your order.<br>";
    echo "You should receive confirmation of your order by email in a few minutes.<br>";
  break;
  case "MALFORMED":
    // The MALFORMED message is only sent if the Transaction Registration POST is poorly formatted. 
// This should not occur in a live environment (in fact, because you have reached this stage your 
// code is already sending correct messages). You should code your FailureURL (this page) to be able to handle 
// messages of this type, however.
  case "INVALID":
    // The INVALID message is only sent if the Transaction Registration POST contains illegal data. 
// Like the MALFORMED message, this should not occur in a live environment, but you should also code 
// your FailureURL (this page) to be able to handle messages of this type.   
   $d['order_status'] = 'X';  //set the new value for the database field: X for cancelled, C for confirmed
    echo "There was a technical problem problem processing this transaction. <br>";
    // Add code to send an email to Tony giving the order number and the username so he can investigate 
  break;
  case "NOTAUTHED":
    // The NOTAUTHED response is sent if the bank has declined the transaction three times. 
// The user has had mutliple chances to enter a valid card but none have been authorised.
  case "REJECTED":
    // The REJECTED message is sent if the banks authorised the payment but the AVS, CV2 or 3D-Secure rulebases 
// you have set up caused the VSP System to automatically cancel that authorisation because those security 
// criteria were not met.   
   $d['order_status'] = 'X';  //set the new value for the database field: X for cancelled, C for confirmed
    echo "Unfortunately your payment request has been declined by your bank. Please contact them for details.<br>";
  break;
  case "ABORT":
    // The ABORT message is sent when the user clicks the Cancel button on the payment page, 
// or if they close their browser, or after 15 minutes of inactivity.
    $d['order_status'] = 'X';  //set the new value for the database field: X for cancelled, C for confirmed
    echo "The order was cancelled.<br>";
  break;
  case "ERROR":
    // The ERROR message is only sent if something has gone wrong at PROTX. You'll receive this message very rarely 
// (occasionally during schedule dmaintenance) but your FailureURL code should be written to handle it.
    $d['order_status'] = 'X';  //set the new value for the database field: X for cancelled, C for confirmed
    echo "We are very sorry but ProTx is not processing payments at the moment. Please try again later.<br>";
  break;     
}

    
$ps_order->order_status_update($d);

}

?>



In the mambo-phpshop component admin, set up a payment method called ProTx CPI. Tick the "active" checkbox. Set the Code to PROTXCPI. Set the payment class name to ps_protx_cpi.


Finally you need to past this code into your mambo database. It goes in a column called payment_extrainfo in a table called mos_pshop_payment_method.

<?php
// This code goes into the database and is eval'ed
print "<Form Action=\\"".$_SESSION['ProTX0_Post']."\\" Method=\\"POST\\" Name=\\"protx\\">\\n";
foreach(
$_SESSION as $name=>$value)
 {
 if(
substr($name,0,7)=='ProTX1_')
  {
  
$name=substr($name,7);
  
$name=str_replace("<","&lt;",$name);
  
$name=str_replace(">","&gt;",$name);
  
$name=str_replace("\\"","&quot;",$name);
  
$name=str_replace("&","&amp;",$name);
  
$value=str_replace("<","&lt;",$value);
  
$value=str_replace(">","&gt;",$value);
  
$value=str_replace("\\"","&quot;",$value);
  
$value=str_replace("&","&amp;",$value);
  print 
"<Input Type=\\"hidden\\" Name=\\"$name\\" Value=\\"$value\\">\\n";
  }
 }
print 
"<Input Type=\\"submit\\" Value=\\"Make Payment\\">\\n";
print 
"</Form>\\n";
print 
"<Script Language=\\"JavaScript\\">\\n";
print 
"document.protx.submit();\\n";
print 
"</Script>\\n";
?>


NB: be careful not to editing this code in the payment method form (under the configuration tab) as you will lose backslashes and the code will cease to work. If you have to change the code, do it in the database using something like phpMyAdmin.

I did find a problem with another mambo-phpshop class method when the line

$ps_order->order_status_update($d);

is executed in checkout.protx_cpi_result.php.

In the file ps_order.php in directory httpdocs/CMS/administrator/components/com_phpshop/classes there is a function called mail_download_id.  In here you need to change this:

   } elseif ($d["order_status"]==DISABLE_DOWNLOAD_STATUS) {
      $q = "DELETE FROM #__pshop_product_download WHERE order_id='".$d['order_id']."'";
      $result = $db->query($q); 
      $db->next_record();

   }

to this:

   } elseif ($d["order_status"]==DISABLE_DOWNLOAD_STATUS) {
      $db = new ps_DB; // 27Aug2005 - NHW:  This line was missing and is required for the subsequent ps_DB method calls to work
      $q = "DELETE FROM #__pshop_product_download WHERE order_id='".$d['order_id']."'";
      $result = $db->query($q); 
      $db->next_record();

   }


Hope this helps a few folks...

Cheers,
Nick.