服务报价 | 域名主机 | 网络营销 | 软件工具| [加入收藏]
 热线电话: #
当前位置: 主页 > php教程 > zencart教程 >

实现Zencart订单类似淘宝后台修改订单价格功能

时间:2016-01-10 02:25来源:未知 作者:最模板 点击:
Zencart 使用 Paypal 付款,会出现漏单的情况,即 paypal 已经收到客户的付款,但是网站后台没有客户的订单。导致 paypal 漏单的原因大致会是当客户跳转到Paypal 网站付款完毕之后,直接关

Zencart 使用 Paypal 付款,会出现漏单的情况,即 paypal 已经收到客户的付款,但是网站后台没有客户的订单。导致 paypal 漏单的原因大致会是当客户跳转到Paypal 网站付款完毕之后,直接关闭了窗口,或者网络不稳定,没有正常跳转到网站。

解决 Paypal 漏单问题的方案有好几种:

 

一. 开启 Detailed Line Items in Cart 选项。

原理:在 zencart 后台 Module --> Payment --> PayPal Website Payments Standard - IPN 开启 Detailed Line Items in Cart 选项。这个选项会把你所有的订单物品信息传给 paypal,当客户付款成功而后台未能成功生成订单时,也可以通过 paypal 帐号交易信息看到客户购买了哪些物品。

 

二. 使用 Paypal Sessions Viewer 插件找回 Paypal 漏掉的订单。

原理:zencart 购物车的物品,通过 paypal 方式付款,会在 paypal_session 表中保存此次付款的所有记录,如果付款成功后,从 paypal 网站跳转到购物网站并生成了订单时,zencart系统会自动删除这条 paypal_session 记录,如果没有成功跳转到购物网站,没有成功生成订单,那这条付款记录数据就会一直保存在数据库,当使用 Paypal Session Viewer 插件,就能查看这条记录的所有数据,包括客户信息,购物时间,商品信息,如果你确定已收到款,就可以把这条 paypal_session 信息转移到订单中,生成一个订单。

插件下载地址:http://www.zen-cart.cn/english-version-modules/admin-tools/paypal-sessions-viewer

 

三. 修改付款流程,先生成订单后付款。

原理:用过zen-cart的人都知道,zen-cart中下单步骤是下面这样的(其中[]中的表示不是必须的):

1. 购物车(shopping cart)

2. [货运方式(delivery method)]

3. 支付方式(payment method)

4. 订单确认(confirmation)

5. [第三方网站支付]

6. 订单处理(checkout process)——这一步比较重要,因为会在这里将购物车中的信息写入订单

7. 下单成功(checkout success)

这样的流程在正常情况下是没有任何问题的。但是,从第5步到第6部的过程中,用户可能以为付款成功就直接关闭掉网页了,或者由于网络原因造成不能正常跳转到checkout_process页面,这样造成的后果是很严重的,因为订单不能被正常的创建。基于上述的分析, 我们希望稍微地改变一下流程,即在支付之前订单已经创建好了,这样就算在支付时不能从第三方支付网站跳转回来,我们也不会存在用户付款成功却在后台没有订单的情况了。

本人是参照东国先生的这篇 修改zen-cart下单和付款流程以防止漏单 教程去修改的,因为这个教程比较老,而且也没有很全面,所以我根据自己的实际需求,把他做的更完善,更细节化。

经过修改后的蓝图基本是下面这样的:

1. 在checkour_confirmation页面确认订单后,都会直接proccess,并且进入 account_history_info 页面,可以在这里进入付款页面。如下图所示:

2. 如果当时客户没能付款,也可进入自己的后台对历史订单进行付款。如下图所示:

 

3. 未付款的订单,可以在后台修改价格,像淘宝一样拍下宝贝后,店主给你修改价格后再付款一样。如下图所示:

下面我们来正式修改代码,首先我列举出所有要修改的文件:

1. includes/classes/payment.php

2. includes/modules/payment/paypal.php

3. includes/classes/order.php

4. includes/modules/pages/checkout_process/header_php.php

5. includes/modules/pages/account_history_info/header_php.php

6. includes/templates/你的模板目录/templates/tpl_account_history_info_default.php

7. includes/templates/你的模板目录/templates/tpl_account_history_default.php

8. ipn_main_handler.php

9. admin(后台目录)/orders.php

因为先生成订单再付款,付款步骤就会比原来又多了一步,为了简化付款流程,我安装了 Fast And Easy Checkout For Zencart(快速支付) 插件,安装此插件之前,需要安装另外一个插件 Css Js Loader For Zencart,这是快速支付插件的依赖插件。快速支付与先生成订单后支付没什么因果关系,所以如果你不想安装的话完全可以不理。

按步骤修改上面列举的文件:

1. 首先我们需要对现有的支付模块进行一个改造。需要对支付方式的class增加一个字段paynow_action_url,用来表示进行支付的页面 url,另外还需要增加一个函数,paynow_button($order_id),来获取支付表单的参数隐藏域代码。

要增加 paynow_action_url 变量,请在类payment的构造函数中最后加上下面的代码: 

if ( (zen_not_null($module)) && (in_array($module.'.php', $this->modules)) && (isset($GLOBALS[$module]->paynow_action_url)) ) {
        $this->paynow_action_url = $GLOBALS[$module]->paynow_action_url;        
}

要增加paynow_button($order_id)函数,请在payment类的最后一个函数之后加上如下的代码:

function paynow_button($order_id){
    if (is_array($this->modules)) {
      if (is_object($GLOBALS[$this->selected_module])) {
        return $GLOBALS[$this->selected_module]->paynow_button($order_id);
      }
    }
}

2. 以paypal支付方式为例子,说明如何具体实现。这里直接修改 paypal.php 文件,注意备份此文件。代码如下所示,可以看到,这里去掉了对 form_action_url 的指定,并给定了 paynow_action_url,因为我们希望用户点击“确认订单”后直接进入checkout_process,所以如果不指定 form_action_url,那么确认订单的表单就会直接提交到 checkout_process 页面了,而 paynow_action_url 就是 以前的 form_action_url 的值。paynow_button 函数的实现也很简单,这里只是将原先的 process_button() 函数的内容剪切过来而已,只不过我们没有使用全局的$order变量,而是使用 $order = new order($order_id),来重新构造的一个对象,这样做是为在历史订单中显示pay now按钮做准备的。paypal.php修改后的文件如下:
 

<?php
/**
 * paypal.php payment module class for PayPal Website Payments Standard (IPN) method
 *
 * @package paymentMethod
 * @copyright Copyright 2003-2010 Zen Cart Development Team
 * @copyright Portions Copyright 2003 osCommerce
 * @license http://www.zen-cart.com/license/2_0.txt GNU Public License V2.0
 * @version $Id: paypal.php 15735 2010-03-29 07:13:53Z drbyte $
 */
 
define('MODULE_PAYMENT_PAYPAL_TAX_OVERRIDE', 'true');
 
/**
 *  ensure dependencies are loaded
 */
  include_once((IS_ADMIN_FLAG === true ? DIR_FS_CATALOG_MODULES : DIR_WS_MODULES) . 'payment/paypal/paypal_functions.php');
 
/**
 * paypal.php payment module class for PayPal Website Payments Standard (IPN) method
 *
 */
class paypal extends base {
  /**
   * string representing the payment method
   *
   * @var string
   */
  var $code;
  /**
   * $title is the displayed name for this payment method
   *
   * @var string
    */
  var $title;
  /**
   * $description is a soft name for this payment method
   *
   * @var string
    */
  var $description;
  /**
   * $enabled determines whether this module shows or not... in catalog.
   *
   * @var boolean
    */
  var $enabled;
  /**
    * constructor
    *
    * @param int $paypal_ipn_id
    * @return paypal
    */
  function paypal($paypal_ipn_id = '') {
    global $order, $messageStack;
    $this->code = 'paypal';
    $this->codeVersion = '1.3.9';
    if (IS_ADMIN_FLAG === true) {
      $this->title = MODULE_PAYMENT_PAYPAL_TEXT_ADMIN_TITLE; // Payment Module title in Admin
      if (IS_ADMIN_FLAG === true && defined('MODULE_PAYMENT_PAYPAL_IPN_DEBUG') && MODULE_PAYMENT_PAYPAL_IPN_DEBUG != 'Off') $this->title .= '<span class="alert"> (debug mode active)</span>';
      if (IS_ADMIN_FLAG === true && MODULE_PAYMENT_PAYPAL_TESTING == 'Test') $this->title .= '<span class="alert"> (dev/test mode active)</span>';
    } else {
      $this->title = MODULE_PAYMENT_PAYPAL_TEXT_CATALOG_TITLE; // Payment Module title in Catalog
    }
    $this->description = MODULE_PAYMENT_PAYPAL_TEXT_DESCRIPTION;
    $this->sort_order = MODULE_PAYMENT_PAYPAL_SORT_ORDER;
    $this->enabled = ((MODULE_PAYMENT_PAYPAL_STATUS == 'True') ? true : false);
    if ((int)MODULE_PAYMENT_PAYPAL_ORDER_STATUS_ID > 0) {
      $this->order_status = MODULE_PAYMENT_PAYPAL_ORDER_STATUS_ID;
    }
    if (is_object($order)) $this->update_status();
    $this->paynow_action_url = 'https://' . MODULE_PAYMENT_PAYPAL_HANDLER;
 
    if (PROJECT_VERSION_MAJOR != '1' && substr(PROJECT_VERSION_MINOR, 0, 3) != '3.9') $this->enabled = false;
 
    // verify table structure
    if (IS_ADMIN_FLAG === true) $this->tableCheckup();
  }
  /**
   * calculate zone matches and flag settings to determine whether this module should display to customers or not
    *
    */
  function update_status() {
    global $order, $db;
 
    if ( ($this->enabled == true) && ((int)MODULE_PAYMENT_PAYPAL_ZONE > 0) ) {
      $check_flag = false;
      $check_query = $db->Execute("select zone_id from " . TABLE_ZONES_TO_GEO_ZONES . " where geo_zone_id = '" . MODULE_PAYMENT_PAYPAL_ZONE . "' and zone_country_id = '" . $order->billing['country']['id'] . "' order by zone_id");
      while (!$check_query->EOF) {
        if ($check_query->fields['zone_id'] < 1) {
          $check_flag = true;
          break;
        } elseif ($check_query->fields['zone_id'] == $order->billing['zone_id']) {
          $check_flag = true;
          break;
        }
        $check_query->MoveNext();
      }
 
      if ($check_flag == false) {
        $this->enabled = false;
      }
    }
  }
  /**
   * JS validation which does error-checking of data-entry if this module is selected for use
   * (Number, Owner, and CVV Lengths)
   *
   * @return string
    */
  function javascript_validation() {
    return false;
  }
  /**
   * Displays payment method name along with Credit Card Information Submission Fields (if any) on the Checkout Payment Page
   *
   * @return array
    */
  function selection() {
    return array('id' => $this->code,
                 'module' => MODULE_PAYMENT_PAYPAL_TEXT_CATALOG_LOGO,
                 'icon' => MODULE_PAYMENT_PAYPAL_TEXT_CATALOG_LOGO
                 );
  }
  /**
   * Normally evaluates the Credit Card Type for acceptance and the validity of the Credit Card Number & Expiration Date
   * Since paypal module is not collecting info, it simply skips this step.
   *
   * @return boolean
   */
  function pre_confirmation_check() {
    return false;
  }
  /**
   * Display Credit Card Information on the Checkout Confirmation Page
   * Since none is collected for paypal before forwarding to paypal site, this is skipped
   *
   * @return boolean
    */
  function confirmation() {
    return false;
  }
  /**
   * Build the data and actions to process when the "Submit" button is pressed on the order-confirmation screen.
   * This sends the data to the payment gateway for processing.
   * (These are hidden fields on the checkout confirmation page)
   *
   * @return string
    */
  function process_button() {
    return false;
  }
  /**
   * Determine the language to use when visiting the PayPal site
   */
  function getLanguageCode() {
    global $order;
    $lang_code = '';
    $orderISO = zen_get_countries($order->customer['country']['id'], true);
    $storeISO = zen_get_countries(STORE_COUNTRY, true);
    if (in_array(strtoupper($orderISO['countries_iso_code_2']), array('US', 'AU', 'DE', 'FR', 'IT', 'GB', 'ES', 'AT', 'BE', 'CA', 'CH', 'CN', 'NL', 'PL'))) {
      $lang_code = strtoupper($orderISO['countries_iso_code_2']);
    } elseif (in_array(strtoupper($storeISO['countries_iso_code_2']), array('US', 'AU', 'DE', 'FR', 'IT', 'GB', 'ES', 'AT', 'BE', 'CA', 'CH', 'CN', 'NL', 'PL'))) {
      $lang_code = strtoupper($storeISO['countries_iso_code_2']);
    } elseif (in_array(strtoupper($_SESSION['languages_code']), array('EN', 'US', 'AU', 'DE', 'FR', 'IT', 'GB', 'ES', 'AT', 'BE', 'CA', 'CH', 'CN', 'NL', 'PL'))) {
      $lang_code = $_SESSION['languages_code'];
      if (strtoupper($lang_code) == 'EN') $lang_code = 'US';
    }
    //return $orderISO['countries_iso_code_2'];
    return strtoupper($lang_code);
  }
  /**
   * Store transaction info to the order and process any results that come back from the payment gateway
   */
  function before_process() {
    return false;
  }
  /**
    * Checks referrer
    *
    * @param string $zf_domain
    * @return boolean
    */
  function check_referrer($zf_domain) {
    return true;
  }
  /**
    * Build admin-page components
    *
    * @param int $zf_order_id
    * @return string
    */
  function admin_notification($zf_order_id) {
    global $db;
    $output = '';
    $sql = "select * from " . TABLE_PAYPAL . " where order_id = '" . (int)$zf_order_id . "' order by paypal_ipn_id DESC LIMIT 1";
    $ipn = $db->Execute($sql);
    if ($ipn->RecordCount() > 0 && file_exists(DIR_FS_CATALOG . DIR_WS_MODULES . 'payment/paypal/paypal_admin_notification.php')) require(DIR_FS_CATALOG . DIR_WS_MODULES . 'payment/paypal/paypal_admin_notification.php');
    return $output;
  }
  /**
   * Post-processing activities
   * When the order returns from the processor, if PDT was successful, this stores the results in order-status-history and logs data for subsequent reference
   *
   * @return boolean
    */
  function after_process() {
    return false;
  }
  /**
   * Used to display error message details
   *
   * @return boolean
    */
  function output_error() {
    return false;
  }
  /**
   * Check to see whether module is installed
   *
   * @return boolean
    */
  function check() {
    global $db;
    if (IS_ADMIN_FLAG === true) {
      global $sniffer;
      if ($sniffer->field_exists(TABLE_PAYPAL, 'zen_order_id'))  $db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE COLUMN zen_order_id order_id int(11) NOT NULL default '0'");
    }
    if (!isset($this->_check)) {
      $check_query = $db->Execute("select configuration_value from " . TABLE_CONFIGURATION . " where configuration_key = 'MODULE_PAYMENT_PAYPAL_STATUS'");
      $this->_check = $check_query->RecordCount();
    }
    return $this->_check;
  }
  /**
   * Install the payment module and its configuration settings
    *
    */
  function install() {
    global $db, $messageStack;
    if (defined('MODULE_PAYMENT_PAYPAL_STATUS')) {
      $messageStack->add_session('PayPal Website Payments Standard module already installed.', 'error');
      zen_redirect(zen_href_link(FILENAME_MODULES, 'set=payment&module=paypal', 'NONSSL'));
      return 'failed';
    }
    if (defined('MODULE_PAYMENT_PAYPALWPP_STATUS')) {
      $messageStack->add_session('NOTE: PayPal Express Checkout module already installed. You don\'t need Standard if you have Express installed.', 'error');
      zen_redirect(zen_href_link(FILENAME_MODULES, 'set=payment&module=paypalwpp', 'NONSSL'));
      return 'failed';
    }
    $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Enable PayPal Module', 'MODULE_PAYMENT_PAYPAL_STATUS', 'True', 'Do you want to accept PayPal payments?', '6', '0', 'zen_cfg_select_option(array(\'True\', \'False\'), ', now())");
    $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Business ID', 'MODULE_PAYMENT_PAYPAL_BUSINESS_ID','".STORE_OWNER_EMAIL_ADDRESS."', 'Primary email address for your PayPal account.<br />NOTE: This must match <strong>EXACTLY </strong>the primary email address on your PayPal account settings.  It <strong>IS case-sensitive</strong>, so please check your PayPal profile preferences at paypal.com and be sure to enter the EXACT same primary email address here.', '6', '2', now())");
    $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Transaction Currency', 'MODULE_PAYMENT_PAYPAL_CURRENCY', 'Selected Currency', 'Which currency should the order be sent to PayPal as? <br />NOTE: if an unsupported currency is sent to PayPal, it will be auto-converted to USD.', '6', '3', 'zen_cfg_select_option(array(\'Selected Currency\', \'Only USD\', \'Only AUD\', \'Only CAD\', \'Only EUR\', \'Only GBP\', \'Only CHF\', \'Only CZK\', \'Only DKK\', \'Only HKD\', \'Only HUF\', \'Only JPY\', \'Only NOK\', \'Only NZD\', \'Only PLN\', \'Only SEK\', \'Only SGD\', \'Only THB\', \'Only MXN\', \'Only ILS\', \'Only PHP\', \'Only TWD\', \'Only BRL\', \'Only MYR\'), ', now())");
    $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, use_function, set_function, date_added) values ('Payment Zone', 'MODULE_PAYMENT_PAYPAL_ZONE', '0', 'If a zone is selected, only enable this payment method for that zone.', '6', '4', 'zen_get_zone_class_title', 'zen_cfg_pull_down_zone_classes(', now())");
    $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, use_function, date_added) values ('Set Pending Notification Status', 'MODULE_PAYMENT_PAYPAL_PROCESSING_STATUS_ID', '" . DEFAULT_ORDERS_STATUS_ID .  "', 'Set the status of orders made with this payment module that are not yet completed to this value<br />(\'Pending\' recommended)', '6', '5', 'zen_cfg_pull_down_order_statuses(', 'zen_get_order_status_name', now())");
    $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, use_function, date_added) values ('Set Order Status', 'MODULE_PAYMENT_PAYPAL_ORDER_STATUS_ID', '2', 'Set the status of orders made with this payment module that have completed payment to this value<br />(\'Processing\' recommended)', '6', '6', 'zen_cfg_pull_down_order_statuses(', 'zen_get_order_status_name', now())");
    $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, use_function, date_added) values ('Set Refund Order Status', 'MODULE_PAYMENT_PAYPAL_REFUND_ORDER_STATUS_ID', '1', 'Set the status of orders that have been refunded made with this payment module to this value<br />(\'Pending\' recommended)', '6', '7', 'zen_cfg_pull_down_order_statuses(', 'zen_get_order_status_name', now())");
    $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Sort order of display.', 'MODULE_PAYMENT_PAYPAL_SORT_ORDER', '0', 'Sort order of display. Lowest is displayed first.', '6', '8', now())");
    $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Address Override', 'MODULE_PAYMENT_PAYPAL_ADDRESS_OVERRIDE', '1', 'If set to 1, the customer shipping address selected in Zen Cart will override the customer PayPal-stored address book. The customer will see their address from Zen Cart, but will NOT be able to edit it at PayPal.<br />(An invalid address will be treated by PayPal as not-supplied, or override=0)<br />0=No Override<br />1=ZC address overrides PayPal address choices', '6', '18', 'zen_cfg_select_option(array(\'0\',\'1\'), ', now())");
    $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Shipping Address Requirements?', 'MODULE_PAYMENT_PAYPAL_ADDRESS_REQUIRED', '2', 'The buyers shipping address. If set to 0 your customer will be prompted to include a shipping address. If set to 1 your customer will not be asked for a shipping address. If set to 2 your customer will be required to provide a shipping address.<br />0=Prompt<br />1=Not Asked<br />2=Required<br /><br /><strong>NOTE: If you allow your customers to enter their own shipping address, then MAKE SURE you PERSONALLY manually verify the PayPal confirmation details to verify the proper address when filling orders. When using Website Payments Standard (IPN), Zen Cart does not know if they choose an alternate shipping address at PayPal vs the one entered when placing an order.</strong>', '6', '20', 'zen_cfg_select_option(array(\'0\',\'1\',\'2\'), ', now())");
    $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Detailed Line Items in Cart', 'MODULE_PAYMENT_PAYPAL_DETAILED_CART', 'No', 'Do you want to give line-item details to PayPal?  If set to True, line-item details will be shared with PayPal if no discounts apply and if tax and shipping are simple. Otherwise an Aggregate cart summary will be sent.', '6', '22', 'zen_cfg_select_option(array(\'No\',\'Yes\'), ', now())");
    $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Page Style', 'MODULE_PAYMENT_PAYPAL_PAGE_STYLE', 'Primary', 'Sets the Custom Payment Page Style for payment pages. The value of page_style is the same as the Page Style Name you chose when adding or editing the page style. You can add and edit Custom Payment Page Styles from the Profile subtab of the My Account tab on the PayPal site. If you would like to always reference your Primary style, set this to \"primary.\" If you would like to reference the default PayPal page style, set this to \"paypal\".', '6', '25', now())");
    $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Mode for PayPal web services<br /><br />Default:<br /><code>www.paypal.com/cgi-bin/webscr</code><br />or<br /><code>www.paypal.com/us/cgi-bin/webscr</code><br />or for the UK,<br /><code>www.paypal.com/uk/cgi-bin/webscr</code>', 'MODULE_PAYMENT_PAYPAL_HANDLER', 'www.paypal.com/cgi-bin/webscr', 'Choose the URL for PayPal live processing', '6', '73', '', now())");
    // sandbox:  www.sandbox.paypal.com/cgi-bin/webscr
    $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added, use_function) values ('PDT Token (Payment Data Transfer)', 'MODULE_PAYMENT_PAYPAL_PDTTOKEN', '', 'Enter your PDT Token value here in order to activate transactions immediately after processing (if they pass validation).', '6', '25', now(), 'zen_cfg_password_display')");
    // Paypal testing options here
    $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Debug Mode', 'MODULE_PAYMENT_PAYPAL_IPN_DEBUG', 'Off', 'Enable debug logging? <br />NOTE: This can REALLY clutter your email inbox!<br />Logging goes to the /includes/modules/payment/paypal/logs folder<br />Email goes to the store-owner address.<br />Email option NOT recommended.<br /><strong>Leave OFF for normal operation.</strong>', '6', '71', 'zen_cfg_select_option(array(\'Off\',\'Log File\',\'Log and Email\'), ', now())");
    $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Debug Email Address', 'MODULE_PAYMENT_PAYPAL_DEBUG_EMAIL_ADDRESS','".STORE_OWNER_EMAIL_ADDRESS."', 'The email address to use for PayPal debugging', '6', '72', now())");
 
    $this->notify('NOTIFY_PAYMENT_PAYPAL_INSTALLED');
  }
  /**
   * Remove the module and all its settings
    *
    */
  function remove() {
    global $db;
    $db->Execute("delete from " . TABLE_CONFIGURATION . " where configuration_key LIKE 'MODULE\_PAYMENT\_PAYPAL\_%'");
    $this->notify('NOTIFY_PAYMENT_PAYPAL_UNINSTALLED');
  }
  /**
   * Internal list of configuration keys used for configuration of the module
   *
   * @return array
    */
  function keys() {
    $keys_list = array(
                       'MODULE_PAYMENT_PAYPAL_STATUS',
                       'MODULE_PAYMENT_PAYPAL_BUSINESS_ID',
                       'MODULE_PAYMENT_PAYPAL_PDTTOKEN',
                       'MODULE_PAYMENT_PAYPAL_CURRENCY',
                       'MODULE_PAYMENT_PAYPAL_ZONE',
                       'MODULE_PAYMENT_PAYPAL_PROCESSING_STATUS_ID',
                       'MODULE_PAYMENT_PAYPAL_ORDER_STATUS_ID',
                       'MODULE_PAYMENT_PAYPAL_REFUND_ORDER_STATUS_ID',
                       'MODULE_PAYMENT_PAYPAL_SORT_ORDER',
                       'MODULE_PAYMENT_PAYPAL_DETAILED_CART',
                       'MODULE_PAYMENT_PAYPAL_ADDRESS_OVERRIDE' ,
                       'MODULE_PAYMENT_PAYPAL_ADDRESS_REQUIRED' ,
                       'MODULE_PAYMENT_PAYPAL_PAGE_STYLE' ,
                       'MODULE_PAYMENT_PAYPAL_HANDLER',
                       'MODULE_PAYMENT_PAYPAL_IPN_DEBUG',
                        );
 
    // Paypal testing/debug options go here:
    if (IS_ADMIN_FLAG === true) {
      if (isset($_GET['debug']) && $_GET['debug']=='on') {
        $keys_list[]='MODULE_PAYMENT_PAYPAL_DEBUG_EMAIL_ADDRESS';  /* this defaults to store-owner-email-address */
      }
    }
    return $keys_list;
  }
 
  function _getPDTresults($orderAmount, $my_currency, $pdtTX) {
    global $db;
    $ipnData  = ipn_postback('PDT', $pdtTX);
    $respdata = $ipnData['info'];
 
    // parse the data
    $lines = explode("\n", $respdata);
    $this->pdtData = array();
    for ($i=1; $i<count($lines);$i++){
      if (!strstr($lines[$i], "=")) continue;
      list($key,$val) = explode("=", $lines[$i]);
      $this->pdtData[urldecode($key)] = urldecode($val);
    }
 
    if ($this->pdtData['txn_id'] == '' || $this->pdtData['payment_status'] == '') {
      ipn_debug_email('PDT Returned INVALID Data. Must wait for IPN to process instead. ' . "\n" . print_r($this->pdtData, true));
      return FALSE;
    } else {
      ipn_debug_email('PDT Returned Data ' . print_r($this->pdtData, true));
    }
 
    $_POST['mc_gross'] = $this->pdtData['mc_gross'];
    $_POST['mc_currency'] = $this->pdtData['mc_currency'];
    $_POST['business'] = $this->pdtData['business'];
    $_POST['receiver_email'] = $this->pdtData['receiver_email'];
 
    $PDTstatus = (ipn_validate_transaction($respdata, $this->pdtData, 'PDT') && valid_payment($orderAmount, $my_currency, 'PDT') && $this->pdtData['payment_status'] == 'Completed');
    if ($this->pdtData['payment_status'] != '' && $this->pdtData['payment_status'] != 'Completed') {
      ipn_debug_email('PDT WARNING :: Order not marked as "Completed".  Check for Pending reasons or wait for IPN to complete.' . "\n" . '[payment_status] => ' . $this->pdtData['payment_status'] . "\n" . '[pending_reason] => ' . $this->pdtData['pending_reason']);
    }
 
    $sql = "SELECT order_id, paypal_ipn_id, payment_status, txn_type, pending_reason
                FROM " . TABLE_PAYPAL . "
                WHERE txn_id = :transactionID OR parent_txn_id = :transactionID
                ORDER BY order_id DESC  ";
    $sql = $db->bindVars($sql, ':transactionID', $this->pdtData['txn_id'], 'string');
    $ipn_id = $db->Execute($sql);
    if ($ipn_id->RecordCount() != 0) {
      ipn_debug_email('PDT WARNING :: Transaction already exists. Perhaps IPN already added it.  PDT processing ended.');
      $pdtTXN_is_unique = false;
    } else {
      $pdtTXN_is_unique = true;
    }
 
    $PDTstatus = ($pdtTXN_is_unique && $PDTstatus);
 
    return $PDTstatus;
  }
 
 
  function tableCheckup() {
    global $db, $sniffer;
    $fieldOkay1 = (method_exists($sniffer, 'field_type')) ? $sniffer->field_type(TABLE_PAYPAL, 'txn_id', 'varchar(20)', true) : -1;
    $fieldOkay2 = ($sniffer->field_exists(TABLE_PAYPAL, 'module_name')) ? true : -1;
    $fieldOkay3 = ($sniffer->field_exists(TABLE_PAYPAL, 'order_id')) ? true : -1;
 
    if ($fieldOkay1 == -1) {
      $sql = "show fields from " . TABLE_PAYPAL;
      $result = $db->Execute($sql);
      while (!$result->EOF) {
        if  ($result->fields['Field'] == 'txn_id') {
          if  ($result->fields['Type'] == 'varchar(20)') {
            $fieldOkay1 = true; // exists and matches required type, so skip to other checkup
          } else {
            $fieldOkay1 = $result->fields['Type']; // doesn't match, so return what it "is"
            break;
          }
        }
        $result->MoveNext();
      }
    }
 
    if ($fieldOkay1 !== true) {
      // temporary fix to table structure for v1.3.7.x -- may remove in later release
      $db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE payment_type payment_type varchar(40) NOT NULL default ''");
      $db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE txn_type txn_type varchar(40) NOT NULL default ''");
      $db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE payment_status payment_status varchar(32) NOT NULL default ''");
      $db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE reason_code reason_code varchar(40) default NULL");
      $db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE pending_reason pending_reason varchar(32) default NULL");
      $db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE invoice invoice varchar(128) default NULL");
      $db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE payer_business_name payer_business_name varchar(128) default NULL");
      $db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE address_name address_name varchar(64) default NULL");
      $db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE address_street address_street varchar(254) default NULL");
      $db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE address_city address_city varchar(120) default NULL");
      $db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE address_state address_state varchar(120) default NULL");
      $db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE payer_email payer_email varchar(128) NOT NULL default ''");
      $db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE business business varchar(128) NOT NULL default ''");
      $db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE receiver_email receiver_email varchar(128) NOT NULL default ''");
      $db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE txn_id txn_id varchar(20) NOT NULL default ''");
      $db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE parent_txn_id parent_txn_id varchar(20) default NULL");
    }
    if ($fieldOkay2 !== true) {
      $db->Execute("ALTER TABLE " . TABLE_PAYPAL . " ADD COLUMN module_name varchar(40) NOT NULL default '' after txn_type");
      $db->Execute("ALTER TABLE " . TABLE_PAYPAL . " ADD COLUMN module_mode varchar(40) NOT NULL default '' after module_name");
    }
    if ($fieldOkay3 !== true) {
      $db->Execute("ALTER TABLE " . TABLE_PAYPAL . " CHANGE zen_order_id order_id int(11) NOT NULL default '0'");
    }
  }
  
  function paynow_button($order_id) {
      global $db, $order, $currencies, $currency;
      require_once(DIR_WS_CLASSES . 'order.php');
      $order = new order($order_id);
      $options = array();
      $optionsCore = array();
      $optionsPhone = array();
      $optionsShip = array();
      $optionsLineItems = array();
      $optionsAggregate = array();
      $optionsTrans = array();
      $buttonArray = array();
  
      $this->totalsum = $order->info['total'];
  
      // save the session stuff permanently in case paypal loses the session
      $_SESSION['ppipn_key_to_remove'] = session_id();
      $db->Execute("delete from " . TABLE_PAYPAL_SESSION . " where session_id = '" . zen_db_input($_SESSION['ppipn_key_to_remove']) . "'");
  
      $sql = "insert into " . TABLE_PAYPAL_SESSION . " (session_id, saved_session, expiry) values (
            '" . zen_db_input($_SESSION['ppipn_key_to_remove']) . "',
            '" . base64_encode(serialize($_SESSION)) . "',
            '" . (time() + (1*60*60*24*2)) . "')";
  
      $db->Execute($sql);
  
      $my_currency = select_pp_currency();
      if(!empty($order->info['currency'])){
          $my_currency=$order->info['currency'];
      }
      $this->transaction_currency = $my_currency;
  
      $this->transaction_amount = ($this->totalsum * $currencies->get_value($my_currency));
  
      $telephone = preg_replace('/\D/', '', $order->customer['telephone']);
      if ($telephone != '') {
          $optionsPhone['H_PhoneNumber'] = $telephone;
          if (in_array($order->customer['country']['iso_code_2'], array('US','CA'))) {
              $optionsPhone['night_phone_a'] = substr($telephone,0,3);
              $optionsPhone['night_phone_b'] = substr($telephone,3,3);
              $optionsPhone['night_phone_c'] = substr($telephone,6,4);
              $optionsPhone['day_phone_a'] = substr($telephone,0,3);
              $optionsPhone['day_phone_b'] = substr($telephone,3,3);
              $optionsPhone['day_phone_c'] = substr($telephone,6,4);
          } else {
              $optionsPhone['night_phone_b'] = $telephone;
              $optionsPhone['day_phone_b'] = $telephone;
          }
      }
  
      $optionsCore = array(
          'lc' => US,
          //'lc' => $order->customer['country']['iso_code_2'],
          'charset' => CHARSET,
          'page_style' => MODULE_PAYMENT_PAYPAL_PAGE_STYLE,
          'custom' => zen_session_name() . '=' . zen_session_id(),
          'invoice' => $order->info['num'],
          'business' => MODULE_PAYMENT_PAYPAL_BUSINESS_ID,
          'return' => zen_href_link(FILENAME_CHECKOUT_PROCESS, 'referer=paypal', 'SSL'),
          'cancel_return' => zen_href_link(FILENAME_CHECKOUT_PAYMENT, '', 'SSL'),
          'shopping_url' => zen_href_link(FILENAME_SHOPPING_CART, '', 'SSL'),
          'notify_url' => zen_href_link('ipn_main_handler.php', '', 'SSL',false,false,true),
          'redirect_cmd' => '_xclick','rm' => 2,'bn' => 'zencart','mrb' => 'R-6C7952342H795591R','pal' => '9E82WJBKKGPLQ',
      );
      $optionsCust = array(
          'first_name' => replace_accents($order->customer['firstname']),
          'last_name' => replace_accents($order->customer['lastname']),
          'address1' => replace_accents($order->customer['street_address']),
          'city' => replace_accents($order->customer['city']),
          'state' => zen_get_zone_code($order->customer['country']['id'], $order->customer['zone_id'], $order->customer['state']),
          'zip' => $order->customer['postcode'],
          'country' => $order->customer['country']['iso_code_2'],
          'email' => $order->customer['email_address'],
      );
      // address line 2 is optional
      if ($order->customer['suburb'] != '') $optionsCust['address2'] = $order->customer['suburb'];
      // different format for Japanese address layout:
      if ($order->customer['country']['iso_code_2'] == 'JP') $optionsCust['zip'] = substr($order->customer['postcode'], 0, 3) . '-' . substr($order->customer['postcode'], 3);
      if (MODULE_PAYMENT_PAYPAL_ADDRESS_REQUIRED == 2) {
          $optionsCust = array(
              'first_name' => replace_accents($order->delivery['firstname'] != '' ? $order->delivery['firstname'] : $order->billing['firstname']),
              'last_name' => replace_accents($order->delivery['lastname'] != '' ? $order->delivery['lastname'] : $order->billing['lastname']),
              'address1' => replace_accents($order->delivery['street_address'] != '' ? $order->delivery['street_address'] : $order->billing['street_address']),
              'city' => replace_accents($order->delivery['city'] != '' ? $order->delivery['city'] : $order->billing['city']),
              'state' => ($order->delivery['country']['id'] != '' ? zen_get_zone_code($order->delivery['country']['id'], $order->delivery['zone_id'], $order->delivery['state']) : zen_get_zone_code($order->billing['country']['id'], $order->billing['zone_id'], $order->billing['state'])),
              'zip' => ($order->delivery['postcode'] != '' ? $order->delivery['postcode'] : $order->billing['postcode']),
              'country' => ($order->delivery['country']['title'] != '' ? $order->delivery['country']['title'] : $order->billing['country']['title']),
              'country_code' => ($order->delivery['country']['iso_code_2'] != '' ? $order->delivery['country']['iso_code_2'] : $order->billing['country']['iso_code_2']),
              'email' => $order->customer['email_address'],
          );
          if ($order->delivery['suburb'] != '') $optionsCust['address2'] = $order->delivery['suburb'];
          if ($order->delivery['country']['iso_code_2'] == 'JP') $optionsCust['zip'] = substr($order->delivery['postcode'], 0, 3) . '-' . substr($order->delivery['postcode'], 3);
      }
      $optionsShip['no_shipping'] = MODULE_PAYMENT_PAYPAL_ADDRESS_REQUIRED;
      if (MODULE_PAYMENT_PAYPAL_ADDRESS_OVERRIDE == '1') $optionsShip['address_override'] = MODULE_PAYMENT_PAYPAL_ADDRESS_OVERRIDE;
      // prepare cart contents details where possible
      if (MODULE_PAYMENT_PAYPAL_DETAILED_CART == 'Yes') $optionsLineItems = ipn_getLineItemDetails();
      if (sizeof($optionsLineItems) > 0) {
          $optionsLineItems['cmd'] = '_cart';
          //      $optionsLineItems['num_cart_items'] = sizeof($order->products);
          if (isset($optionsLineItems['shipping'])) {
              $optionsLineItems['shipping_1'] = $optionsLineItems['shipping'];
              unset($optionsLineItems['shipping']);
          }
          unset($optionsLineItems['subtotal']);
          // if line-item details couldn't be kept due to calculation mismatches or discounts etc, default to aggregate mode
          if (!isset($optionsLineItems['item_name_1']) || $optionsLineItems['creditsExist'] == TRUE) $optionsLineItems = array();
          //if ($optionsLineItems['amount'] != $this->transaction_amount) $optionsLineItems = array();
          // debug:
          //ipn_debug_email('Line Item Details (if blank, this means there was a data mismatch or credits applied, and thus bypassed): ' . "\n" . print_r($optionsLineItems, true));
          unset($optionsLineItems['creditsExist']);
      }
      $optionsAggregate = array(
          'cmd' => '_ext-enter',
          'item_name' => MODULE_PAYMENT_PAYPAL_PURCHASE_DESCRIPTION_TITLE,
          'item_number' => MODULE_PAYMENT_PAYPAL_PURCHASE_DESCRIPTION_ITEMNUM,
          //'num_cart_items' => sizeof($order->products),
          'amount' => number_format($this->transaction_amount, $currencies->get_decimal_places($my_currency)),
          'shipping' => '0.00',
      );
      if (MODULE_PAYMENT_PAYPAL_TAX_OVERRIDE == 'true') $optionsAggregate['tax'] = '0.00';
      if (MODULE_PAYMENT_PAYPAL_TAX_OVERRIDE == 'true') $optionsAggregate['tax_cart'] = '0.00';
      $optionsTrans = array(
          'upload' => (int)(sizeof($order->products) > 0),
          'currency_code' => $my_currency,
          //'paypal_order_id' => $paypal_order_id,
          //'no_note' => '1',
          //'invoice' => '',
      );
  
      // if line-item info is invalid, use aggregate:
      if (sizeof($optionsLineItems) > 0) $optionsAggregate = $optionsLineItems;
  
      // prepare submission
      $options = array_merge($optionsCore, $optionsCust, $optionsPhone, $optionsShip, $optionsTrans, $optionsAggregate);
      //ipn_debug_email('Keys for submission: ' . print_r($options, true));
  
      // build the button fields
      foreach ($options as $name => $value) {
          // remove quotation marks
          $value = str_replace('"', '', $value);
          // check for invalid chars
          if (preg_match('/[^a-zA-Z_0-9]/', $name)) {
              ipn_debug_email('datacheck - ABORTING - preg_match found invalid submission key: ' . $name . ' (' . $value . ')');
              break;
          }
          // do we need special handling for & and = symbols?
          //if (strpos($value, '&') !== false || strpos($value, '=') !== false) $value = urlencode($value);
  
          $buttonArray[] = zen_draw_hidden_field($name, $value);
      }
      $process_button_string = implode("\n", $buttonArray) . "\n";
  
      $_SESSION['paypal_transaction_info'] = array($this->transaction_amount, $this->transaction_currency);
      return $process_button_string;
  }
 
}

 

3. 在网站后台 Orders Status(地给你单状态)中,增加一项 Unpaid(未付款)选项。然后修改 Order.php 中 create 方法,指定如果生成订单的时候,客户选择的付款方式是 Paypal,那么此订单的状态将会是 Unpaid状态。代码如下:
 

function create($zf_ot_modules, $zf_mode = 2) {
    global $db;
    $t1 = date("YmdGhs"); 
    srand ((float) microtime() * 10000000); 
    $input = array ("1", "2", "3", "4", "5", "6", "7", "8", "9", "0"); 
    $rand_keys = array_rand ($input, 2); 
    $l1 = $input[$rand_keys[0]]; 
    $l2 = $input[$rand_keys[1]]; 
    $r1 = rand(0,9); 
    $ordernum = $t1.$l1.$l2.$r1; 
 
    if ($this->info['total'] == 0) {
      if (DEFAULT_ZERO_BALANCE_ORDERS_STATUS_ID == 0) {
        $this->info['order_status'] = DEFAULT_ORDERS_STATUS_ID;
      } else {
        if ($_SESSION['payment'] != 'freecharger') {
          $this->info['order_status'] = DEFAULT_ZERO_BALANCE_ORDERS_STATUS_ID;
        }
      }
    }
    //在这个位置增加下面的代码,5是后台添加的Unpaid状态的ID号,不尽相同,注意查看。
    if($_SESSION['payment'] == 'paypal'){
        $this->info['order_status'] = 5;
    }
 

4. 如果是通过Paypal付款后,从Paypal返回网站时,会使用GET方式带入一些数据到 includes/modules/pages/checkout_process/header_php.php 这个页面,而直接生成订单时,并不会有GET数据传输,所以通过 $_GET['referer'] 这条返回值数据,来判断是生成订单,还是付款归来。如果只是生成订单的话,跳转到 tpl_account_history_info_default 页面,如果是付款归来,则跳转到 checkout_success 页面,这样就避免了重复生成订单了。代码如下:
 

$zco_notifier->notify('NOTIFY_HEADER_START_CHECKOUT_PROCESS');
  
  if(isset($_GET['referer']) && $_GET['referer'] == 'paypal'){
      //如果是来自paypal的付款,就直接跳转到付款成功页面
      zen_redirect(zen_href_link(FILENAME_CHECKOUT_SUCCESS, (isset($_GET['action']) && $_GET['action'] == 'confirm' ? 'action=confirm' : ''), 'SSL'));
  }
  else{
      require(DIR_WS_MODULES . zen_get_module_directory('checkout_process.php'));
      
      // load the after_process function from the payment modules
      $payment_modules->after_process();
      
      $_SESSION['cart']->reset(true);
      
      // unregister session variables used during checkout
      unset($_SESSION['sendto']);
      unset($_SESSION['billto']);
      unset($_SESSION['shipping']);
      unset($_SESSION['payment']);
      unset($_SESSION['comments']);
      $order_total_modules->clear_posts();//ICW ADDED FOR CREDIT CLASS SYSTEM
      
      // This should be before the zen_redirect:
      $zco_notifier->notify('NOTIFY_HEADER_END_CHECKOUT_PROCESS');
      
      zen_redirect(zen_href_link(FILENAME_ACCOUNT_HISTORY_INFO, 'order_id='.$insert_id, 'SSL'));
  }
 
  require(DIR_WS_INCLUDES . 'application_bottom.php');

 

5. 在 tpl_account_history_info_default 页面中显示pay now按钮。打开文件"includes/modules/pages/account_history_info/header.php",在文件的末尾添加下 面的代码:

require(DIR_WS_CLASSES . 'order.php');
$order = new order($_GET['order_id']);
 
//在这个位置插入下面两行代码
require_once(DIR_WS_CLASSES . 'payment.php');
$payment_modules = new payment($order->info['payment_module_code']);
 

6. 打开文件"includes/templates/template_default/templates /tpl_account_history_info_default.php",并在适当的位置加上如下的代码,这里对订单的状态进行了一个判断,当只有订单的 状态在未付款状态,才显示该按钮。代码如下:
 

<?php
    //Unpaid是你在后台添加的为付款订单状态
    if(isset($payment_modules->paynow_action_url) && $payment_modules->paynow_action_url != '' && $order->info['orders_status'] == 'Unpaid'){
        echo '<div class="back"><strong>Order has been generated</strong> - please continue to pay</div>';
        echo zen_draw_form('checkout_paynow', $payment_modules->paynow_action_url, 'post', 'id="checkout_confirmation" onsubmit="submitonce();" class="right"');
        echo('<div>');            
        if (is_array($payment_modules->modules)) {          
            echo $payment_modules->paynow_button($_GET['order_id']);
        }
        echo zen_image_submit("button_buy_now.gif", "Pay now this order","name='submit'");
        //echo '<input type="image" src="https://www.sandbox.paypal.com/en_US/i/btn/btn_buynow_LG.gif" border="0" name="submit" alt="PayPal——最安全便捷的在线支付方式!">';
        echo ('</div>');
        echo ('</form>');
    }
?>

 

7. 修改 tpl_account_history_default.php 页面,判断是否为未付款订单,如果是,则增加一个 pay_now 按钮,然后跳转到 tpl_account_history_info_default.php 页面进行付款,其实跟 view 按钮是一样的,只不过换了一个名称,标明是未付款订单而已。

8. 最关键的地方来了,就是 ipn_main_handler.php 这个文件。Paypal 付款接口返回数据方式有两种,一种是PDT,一种是IPN,PDT是同步传输,付款数据会立即返回到网站,并且是一次性的。IPN则是异步传输,而且如果网站没有收到数据,IPN还会再次循环的发送付款信息到你的网站 ipn_main_handler.php 文件进行处理并写入数据库。最终我们在客户订单中,就能看到客户的Paypal付款信息,如下图:

之前的付款流程中,Paypal 付款数据是通过 PDT 方式传输,修改了付款流程之后,我们不能通过 PDT 方式,只能通过 IPN 方式传输。ipn_main_handler.php 文件就是处理 IPN 数据传输方式的文件。不过,当 ipn_main_handler.php 接收到 Paypal 付款数据后,会根据 Paypal 付款数据生成一个订单,但是我们已经有了订单,只需要把 Paypal 付款信息写入到数据库中,与订单对应即可。所以我们需要修改  ipn_main_handler.php 文件。PDT和IPN详细介绍链接:http://wenku.baidu.com/link?url=xI4DZL8mg9R54aJKfn3zNyP9_yFHkHVvxWltEuAZ9-DXXAS3K3z-z6srRlh_P-EmMXYU-U6oQ_uEwNze7An9PBAUgnPMH-b_iF3d2z7LE_G

首先,我们要确定,通过 IPN 方式返回的 Paypal 付款信息是属于哪个订单的,我在 paypal.php 文件中第 470 行增加了 'invoice' => $order->info['id'],作用就是在付款的时候,把这个信息发送给Paypal,付款成功后,Paypal也会通过IPN返回这条信息到 ipn_main_handler.php。根据这个判断,如果接收到了 invoice 数据,则跳过生成订单的步骤,只写入Paypal付款信息即可。代码如下:
 

<?php
/**
 * ipn_main_handler.php callback handler for PayPal IPN notifications
 *
 * @package paymentMethod
 * @copyright Copyright 2003-2010 Zen Cart Development Team
 * @copyright Portions Copyright 2003 osCommerce
 * @license http://www.zen-cart.com/license/2_0.txt GNU Public License V2.0
 * @version $Id: ipn_main_handler.php 18014 2010-10-22 03:39:17Z drbyte $
 */
if (!defined('TEXT_RESELECT_SHIPPING')) define('TEXT_RESELECT_SHIPPING', 'You have changed the items in your cart since shipping was last calculated, and costs may have changed. Please verify/re-select your shipping method.');
 
/**
 * handle Express Checkout processing:
 */
if (isset($_GET['type']) && $_GET['type'] == 'ec') {
  // this is an EC handler request
  require('includes/application_top.php');
 
// Validate Cart for checkout
  $_SESSION['valid_to_checkout'] = true;
  $_SESSION['cart']->get_products(true);
  if ($_SESSION['valid_to_checkout'] == false || $_SESSION['cart']->count_contents() <= 0) {
    $messageStack->add_session('shopping_cart', ERROR_CART_UPDATE, 'error');
    zen_redirect(zen_href_link(FILENAME_SHOPPING_CART));
  }
 
  // Stock Check to prevent checkout if cart contents rules violations exist
  if ( STOCK_CHECK == 'true' && STOCK_ALLOW_CHECKOUT != 'true' && isset($_SESSION['cart']) ) {
    $products = $_SESSION['cart']->get_products();
    for ($i=0, $n=sizeof($products); $i<$n; $i++) {
      if (zen_check_stock($products[$i]['id'], $products[$i]['quantity'])) {
        zen_redirect(zen_href_link(FILENAME_SHOPPING_CART));
        break;
      }
    }
  }
  // if cart contents has changed since last pass, reset
  if (isset($_SESSION['cart']->cartID)) {
    if (isset($_SESSION['cartID'])) {  // This will only be set if customer has been to the checkout_shipping page. Will *not* be set if starting via EC Shortcut button, so don't want to redirect in that case.
      if ($_SESSION['cart']->cartID != $_SESSION['cartID']) {
        if (isset($_SESSION['shipping'])) {
          unset($_SESSION['shipping']);
          $messageStack->add_session('checkout_shipping', TEXT_RESELECT_SHIPPING, 'error');
          zen_redirect(zen_href_link(FILENAME_CHECKOUT_SHIPPING, '', 'SSL'));
        }
      }
    }
//  } else {
//    zen_redirect(zen_href_link(FILENAME_TIME_OUT));
  }
 
  require(DIR_WS_CLASSES . 'payment.php');
  // See if we were sent a request to clear the session for PayPal.
  if (isset($_GET['clearSess']) || isset($_GET['amp;clearSess']) || isset($_GET['ec_cancel']) || isset($_GET['amp;ec_cancel'])) {
    // Unset the PayPal EC information.
    unset($_SESSION['paypal_ec_temp']);
    unset($_SESSION['paypal_ec_token']);
    unset($_SESSION['paypal_ec_payer_id']);
    unset($_SESSION['paypal_ec_payer_info']);
  }
  // See if the paypalwpp module is enabled.
  if (defined('MODULE_PAYMENT_PAYPALWPP_STATUS') && MODULE_PAYMENT_PAYPALWPP_STATUS == 'True') {
    $paypalwpp_module = 'paypalwpp';
    // init the payment object
    $payment_modules = new payment($paypalwpp_module);
    // set the payment, if they're hitting us here then we know
    // the payment method selected right now.
    $_SESSION['payment'] = $paypalwpp_module;
    // check to see if we have a token sent back from PayPal.
    if (!isset($_SESSION['paypal_ec_token']) || empty($_SESSION['paypal_ec_token'])) {
      // We have not gone to PayPal's website yet in order to grab
      // a token at this time.  This will send the customer over to PayPal's
      // website to login and return a token
      $$paypalwpp_module->ec_step1();
    } else {
      // This will push on the second step of the paypal ec payment
      // module, as we already have a PayPal express checkout token
      // at this point.
      $$paypalwpp_module->ec_step2();
    }
  }
?>
<html>
Processing...
</html>
  <?php
 
  /**
   * If we got here, we are an IPN transaction (not Express Checkout):
   */
 
} else {
  /**
   * detect odd cases of extra-url-encoded POST data coming back from PayPal
   */
  foreach(array('receiver_email', 'payer_email', 'business', 'txn_type', 'transaction_subject', 'custom', 'payment_date', 'item_number', 'item_name', 'first_name', 'last_name') as $key) {
    if (isset($_POST[$key]) && strstr($_POST[$key], '%')) {
      $_POST[$key] = urldecode($_POST[$key]);
    }
  }
  /**
   * detect type of transaction
   */
  $isECtransaction = ((isset($_POST['txn_type']) && $_POST['txn_type']=='express_checkout') || (isset($_POST['custom']) && in_array(substr($_POST['custom'], 0, 3), array('EC-', 'DP-', 'WPP')))); /*|| $_POST['txn_type']=='cart'*/
  $isDPtransaction = (isset($_POST['custom']) && in_array(substr($_POST['custom'], 0, 3), array('DP-', 'WPP')));
  /**
   * set paypal-specific application_top parameters
   */
  $current_page_base = 'paypalipn';
  $loaderPrefix = 'paypal_ipn';
  $show_all_errors = FALSE;
  require('includes/application_top.php');
 
  $extraDebug = (defined('IPN_EXTRA_DEBUG_DETAILS') && IPN_EXTRA_DEBUG_DETAILS == 'All');
 
  if (  (defined('MODULE_PAYMENT_PAYPALWPP_DEBUGGING') && strstr(MODULE_PAYMENT_PAYPALWPP_DEBUGGING, 'Log')) ||
      (defined('MODULE_PAYMENT_PAYPAL_IPN_DEBUG') && strstr(MODULE_PAYMENT_PAYPAL_IPN_DEBUG, 'Log')) ||
      ($_REQUEST['ppdebug'] == 'on' && strstr(EXCLUDE_ADMIN_IP_FOR_MAINTENANCE, $_SERVER['REMOTE_ADDR'])) || $extraDebug  ) {
    $show_all_errors = true;
    $debug_logfile_path = ipn_debug_email('Breakpoint: 0 - Initializing debugging.');
    if ($debug_logfile_path == '') $debug_logfile_path = 'includes/modules/payment/paypal/logs/ipn_debug_php_errors-'.time().'.log';
    @ini_set('log_errors', 1);
    @ini_set('log_errors_max_len', 0);
    @ini_set('display_errors', 0); // do not output errors to screen/browser/client (only to log file)
    @ini_set('error_log', DIR_FS_CATALOG . $debug_logfile_path);
    error_reporting(version_compare(PHP_VERSION, 5.3, '>=') ? E_ALL & ~E_DEPRECATED & ~E_NOTICE : version_compare(PHP_VERSION, 6.0, '>=') ? E_ALL & ~E_DEPRECATED & ~E_NOTICE & ~E_STRICT : E_ALL & ~E_NOTICE);
  }
 
  ipn_debug_email('Breakpoint: Flag Status:' . "\nisECtransaction = " . (int)$isECtransaction . "\nisDPtransaction = " . (int)$isDPtransaction);
  /**
   * do confirmation post-back to PayPal and extract the results for subsequent use
   */
  $info  = ipn_postback();
  $new_status = 1;
  ipn_debug_email('Breakpoint: 1 - Collected data from PayPal notification');
 
  /**
   * validate transaction -- email address, matching txn record, etc
   */
  if (!ipn_validate_transaction($info, $_POST, 'IPN') === true) {
    if (!$isECtransaction && $_POST['txn_type'] != '') {
      ipn_debug_email('IPN FATAL ERROR :: Transaction did not validate. ABORTED.');
      die();
    }
  }
 
  if ($isDPtransaction) {
    ipn_debug_email('IPN NOTICE :: This is a Website Payments Pro transaction.  The rest of this log file is INFORMATION ONLY, and is not used for real processing.');
  }
 
  ipn_debug_email('Breakpoint: 2 - Validated transaction components');
  if ($_POST ['exchange_rate'] == '')  $_POST [exchange_rate] = 1;
  if ($_POST ['num_cart_items'] == '') $_POST [num_cart_items] = 1;
  if ($_POST ['settle_amount'] == '')  $_POST [settle_amount] = 0;
 
  /**
   * is this a sandbox transaction?
   */
  if (isset($_POST['test_ipn']) && $_POST['test_ipn'] == 1) {
    ipn_debug_email('IPN NOTICE :: Processing SANDBOX transaction.');
  }
  if (isset($_POST['test_internal']) && $_POST['test_internal'] == 1) {
    ipn_debug_email('IPN NOTICE :: Processing INTERNAL TESTING transaction.');
  }
  if (isset($_POST['pending_reason']) && $_POST['pending_reason'] == 'unilateral') {
    ipn_debug_email('*** NOTE: TRANSACTION IS IN *unilateral* STATUS, pending creation of a PayPal account for this receiver_email address.' . "\n" . 'Please create the account, or make sure the PayPal account is *Verified*.');
  }
 
  ipn_debug_email('Breakpoint: 3 - Communication method verified');
  /**
   * Lookup transaction history information in preparation for matching and relevant updates
   */
  $lookupData  = ipn_lookup_transaction($_POST);
  $ordersID    = $lookupData['order_id'];
  $paypalipnID = $lookupData['paypal_ipn_id'];
  $txn_type    = $lookupData['txn_type'];
  $parentLookup = $txn_type;
 
  ipn_debug_email('Breakpoint: 4 - ' . 'Details:  txn_type=' . $txn_type . '    ordersID = '. $ordersID . '  IPN_id=' . $paypalipnID . "\n\n" . '   Relevant data from POST:' . "\n     " . 'txn_type = ' . $txn_type . "\n     " . 'parent_txn_id = ' . ($_POST['parent_txn_id'] =='' ? 'None' : $_POST['parent_txn_id']) . "\n     " . 'txn_id = ' . $_POST['txn_id']);
 
  if (!$isECtransaction && !isset($_POST['parent_txn_id']) && $txn_type != 'cleared-echeck') {
    if (defined('MODULE_PAYMENT_PAYPAL_PDTTOKEN') && MODULE_PAYMENT_PAYPAL_PDTTOKEN != '') {
      ipn_debug_email('IPN NOTICE :: IPN pausing: waiting for PDT to process. Sleeping 10 seconds ...');
      sleep(10);
    }
    if (ipn_get_stored_session($session_stuff) === false) {
      ipn_debug_email('IPN ERROR :: No pending Website Payments Standard session data available.  Might be a duplicate transaction already entered via PDT.');
      $ipnFoundSession = false;
    }
  }
 
  if ($ipnFoundSession == FALSE && !$isECtransaction && !$isDPtransaction && $txn_type != 'cleared-echeck') {
    ipn_debug_email('NOTICE: IPN Processing Aborted due to missing matching transaction data, as per earlier debug message. Perhaps this transaction was already entered via PDT? Thus there is no need to process this incoming IPN notification.');
    die();
  }
 
  // this is used to determine whether a record needs insertion. ie: original echeck notice failed, but now we have cleared, so need parent record established:
  $new_record_needed = ($txn_type == 'unique' ? true : false);
  /**
   * evaluate what type of transaction we're processing
   */
  $txn_type = ipn_determine_txn_type($_POST, $txn_type);
  ipn_debug_email('Breakpoint: 5 - Transaction type (txn_type) = ' . $txn_type . '   [parentLookup='.$parentLookup.']');
 
  if ($_POST['payment_type'] == 'instant' && $isDPtransaction && ((isset($_POST['auth_status']) && $_POST['auth_status'] == 'Completed') || $_POST['payment_status'] == 'Completed')) {
    ipn_debug_email('IPN NOTICE :: DP/Website Payments Pro notice -- IPN Ignored');
    die();
  }
 
  /**
   * take action based on transaction type and corresponding requirements
   */
  switch ($txn_type) {
    case ($_POST['txn_type'] == 'send_money'):
    case ($_POST['txn_type'] == 'merch_payment'):
    case ($_POST['txn_type'] == 'new_case'):
    case ($_POST['txn_type'] == 'masspay'):
      // these types are irrelevant to ZC transactions
      ipn_debug_email('IPN NOTICE :: Transaction txn_type not relevant to Zen Cart processing. IPN handler aborted.' . $_POST['txn_type']);
      die();
      break;
    case (substr($_POST['txn_type'],0,7) == 'subscr_'):
      // For now we filter out subscription payments
      ipn_debug_email('IPN NOTICE :: Subscription payment - Not currently supported by Zen Cart. IPN handler aborted.');
      die();
      break;
 
    case 'pending-unilateral':
      // cannot process this order because the merchant's PayPal account isn't valid yet
      ipn_debug_email('IPN NOTICE :: Please create a valid PayPal account and follow the steps to *Verify* it. IPN handler aborted.');
      die();
      break;
    case 'pending-address':
    case 'pending-intl':
    case 'pending-multicurrency':
    case 'pending-verify':
      if (!$isECtransaction) {
        ipn_debug_email('IPN NOTICE :: '.$txn_type.' transaction -- inserting initial record for reference purposes');
        $sql_data_array = ipn_create_order_array($ordersID, $txn_type);
        zen_db_perform(TABLE_PAYPAL, $sql_data_array);
        $sql_data_array = ipn_create_order_history_array($paypalipnID);
        zen_db_perform(TABLE_PAYPAL_PAYMENT_STATUS_HISTORY, $sql_data_array);
        die();
        break;
      }
    case (($txn_type == 'express_checkout' || $isECtransaction) && !strstr($txn_type, 'cleared') && $parentLookup != 'parent'):
      if ($_POST['payment_status'] == 'Completed') {
        // This is an express-checkout transaction -- IPN may not be needed
        if (isset($_POST['auth_status']) && $_POST['auth_status'] == 'Completed') {
          ipn_debug_email('IPN NOTICE :: Express Checkout payment notice on completed order -- IPN Ignored');
          die();
        }
      }
      if ($_POST['payment_type'] == 'instant' && isset($_POST['auth_status']) && $_POST['auth_status'] == 'Pending') {
        ipn_debug_email('IPN NOTICE :: EC/DP notice on pre-auth order -- IPN Ignored');
        die();
      }
      ipn_debug_email('Breakpoint: 5 - midstream checkpoint');
      if (!(substr($txn_type,0,8) == 'pending-' && (int)$ordersID <= 0) && !($new_record_needed && $txn_type == 'echeck-cleared') && $txn_type != 'unique' && $txn_type != 'echeck-denied' && $txn_type != 'voided') {
        ipn_debug_email('Breakpoint: 5 - Record does not need to be processed since it is not new and is not an update. See earlier notices. Processing aborted.');
        break;
      }
 
    case ($txn_type == 'cart'):
      ipn_debug_email('IPN NOTICE :: This is a detailed-cart transaction');
 
    case ($txn_type == 'cart' && !$isECtransaction):
      ipn_debug_email('IPN NOTICE :: This is a detailed-cart transaction (i)');
 
    case (substr($txn_type,0,8) == 'pending-' && (int)$ordersID <= 0):
    case ($new_record_needed && $txn_type == 'echeck-cleared'):
    case 'unique':
      /**
       * delete IPN session from PayPal table -- housekeeping
       */
      $db->Execute("delete from " . TABLE_PAYPAL_SESSION . " where session_id = '" . zen_db_input(str_replace('zenid=', '', $_POST['custom'])) . "'");
      /**
       * require shipping class
       */
      require(DIR_WS_CLASSES . 'shipping.php');
      /**
       * require payment class
       */
      require(DIR_WS_CLASSES . 'payment.php');
      $payment_modules = new payment($_SESSION['payment']);
      $shipping_modules = new shipping($_SESSION['shipping']);
      /**
       * require order class
       */
      //这里判断是否获取到了invoice信息,如果获取到,则提取此订单的信息。
      require(DIR_WS_CLASSES . 'order.php');
      if(isset($_POST['invoice']) && $_POST['invoice'] != ''){
          $order = new order($_POST['invoice']);
      }else{
          $order = new order();
      }
      /**
       * require order_total class
       */
      require(DIR_WS_CLASSES . 'order_total.php');
      $order_total_modules = new order_total();
      $zco_notifier->notify('NOTIFY_CHECKOUT_PROCESS_BEFORE_ORDER_TOTALS_PROCESS');
      $order_totals = $order_total_modules->process();
      $zco_notifier->notify('NOTIFY_CHECKOUT_PROCESS_AFTER_ORDER_TOTALS_PROCESS');
 
      if (valid_payment($order->info['total'], $_SESSION['currency']) === false && !$isECtransaction && !$isDPtransaction) {
        ipn_debug_email('IPN NOTICE :: Failed because of currency mismatch.');
        //需要注意此处,这里的付款货币匹配检查,因为在发送付款数据到paypal时,我们就根据顾客的订单货币方式做出了设定。
        //并且客户更改当前默认货币也不能改变以生成的订单的货币种类,所以这里的判断可以取消,不然死在这里。
        //die();
      }
      if ($ipnFoundSession === false && !$isECtransaction && !$isDPtransaction) {
        ipn_debug_email('IPN NOTICE :: Unique but no session - Assumed to be a personal payment, rather than a new Website Payments Standard transaction. Ignoring.');
        die();
      }
      if (!strstr($txn_type, 'denied') && !strstr($txn_type, 'failed') && !strstr($txn_type, 'voided')) {
        //这里判断,如果获取到了invoice,则跳过生产订单的步骤,之写入Paypal付款信息。
        if(isset($_POST['invoice']) && $_POST['invoice'] != ''){
            $insert_id = $_POST['invoice'];
            $zco_notifier->notify('NOTIFY_CHECKOUT_PROCESS_AFTER_ORDER_CREATE');
            ipn_debug_email('Breakpoint: 5a - built order -- OID: ' . $insert_id);
            $sql_data_array = ipn_create_order_array($insert_id, $txn_type);
            ipn_debug_email('Breakpoint: 5b - PP table OID: ' . print_r($sql_data_array, true));
            zen_db_perform(TABLE_PAYPAL, $sql_data_array);
            ipn_debug_email('Breakpoint: 5c - PP table OID saved');
            $pp_hist_id = $db->Insert_ID();
            $zco_notifier->notify('NOTIFY_CHECKOUT_PROCESS_AFTER_PAYMENT_MODULES_AFTER_ORDER_CREATE');
            ipn_debug_email('Breakpoint: 5d - PP hist ID: ' . $pp_hist_id);
            $sql_data_array = ipn_create_order_history_array($pp_hist_id);
            ipn_debug_email('Breakpoint: 5e - PP hist_data:' . print_r($sql_data_array, true));
            zen_db_perform(TABLE_PAYPAL_PAYMENT_STATUS_HISTORY, $sql_data_array);
            ipn_debug_email('Breakpoint: 5f - PP hist saved');
            $new_status = MODULE_PAYMENT_PAYPAL_ORDER_STATUS_ID;
            ipn_debug_email('Breakpoint: 5g - new status code: ' . $new_status);
            if ($_POST['payment_status'] =='Pending') {
                $new_status = (defined('MODULE_PAYMENT_PAYPAL_PROCESSING_STATUS_ID') && (int)MODULE_PAYMENT_PAYPAL_PROCESSING_STATUS_ID > 0 ? (int)MODULE_PAYMENT_PAYPAL_PROCESSING_STATUS_ID : 2);
                ipn_debug_email('Breakpoint: 5h - newer status code: ' . (int)$new_status);
                $sql = "UPDATE " . TABLE_ORDERS  . "
                  SET orders_status = " . (int)$new_status . "
                  WHERE orders_id = '" . (int)$insert_id . "'";
                $db->Execute($sql);
                ipn_debug_email('Breakpoint: 5i - order table updated');
            }
            $sql_data_array = array('orders_id' => (int)$insert_id,
                'orders_status_id' => (int)$new_status,
                'date_added' => 'now()',
                'comments' => 'PayPal status: ' . $_POST['payment_status'] . ' ' . $_POST['pending_reason']. ' @ '.$_POST['payment_date'] . (($_POST['parent_txn_id'] !='') ? "\n" . ' Parent Trans ID:' . $_POST['parent_txn_id'] : '') . "\n" . ' Trans ID:' . $_POST['txn_id'] . "\n" . ' Amount: ' . $_POST['mc_gross'] . ' ' . $_POST['mc_currency'],
                'customer_notified' => 0
            );
            if ($_POST['payment_status'] =='Completed') {
                $new_status = (defined('MODULE_PAYMENT_PAYPAL_ORDER_STATUS_ID') && (int)MODULE_PAYMENT_PAYPAL_ORDER_STATUS_ID > 0 ? (int)MODULE_PAYMENT_PAYPAL_ORDER_STATUS_ID : 2);
                ipn_debug_email('Breakpoint: 5h_1 - newer status code: ' . (int)$new_status);
                $sql = "UPDATE " . TABLE_ORDERS  . "
                  SET orders_status = " . (int)$new_status . "
                  WHERE orders_id = '" . (int)$insert_id . "'";
                $db->Execute($sql);
                ipn_debug_email('Breakpoint: 5i_1 - order table updated');
            }
            $sql_data_array = array('orders_id' => (int)$insert_id,
                'orders_status_id' => (int)$new_status,
                'date_added' => 'now()',
                'comments' => 'PayPal status: ' . $_POST['payment_status'] . ' ' . $_POST['pending_reason']. ' @ '.$_POST['payment_date'] . (($_POST['parent_txn_id'] !='') ? "\n" . ' Parent Trans ID:' . $_POST['parent_txn_id'] : '') . "\n" . ' Trans ID:' . $_POST['txn_id'] . "\n" . ' Amount: ' . $_POST['mc_gross'] . ' ' . $_POST['mc_currency'],
                'customer_notified' => 0
            );
            ipn_debug_email('Breakpoint: 5j - order stat hist update:' . print_r($sql_data_array, true));
            zen_db_perform(TABLE_ORDERS_STATUS_HISTORY, $sql_data_array);
            if (MODULE_PAYMENT_PAYPAL_ADDRESS_OVERRIDE == '1') {
                $sql_data_array['comments'] = '**** ADDRESS OVERRIDE ALERT!!! **** CHECK PAYPAL ORDER DETAILS FOR ACTUAL ADDRESS SELECTED BY CUSTOMER!!';
                $sql_data_array['customer_notified'] = -1;
            }
            zen_db_perform(TABLE_ORDERS_STATUS_HISTORY, $sql_data_array);
            ipn_debug_email('Breakpoint: 5k - OSH update done');
            //$order->create_add_products($insert_id, 2);
            ipn_debug_email('Breakpoint: 5L - adding products');
            $_SESSION['order_number_created'] = $insert_id;
            $zco_notifier->notify('NOTIFY_CHECKOUT_PROCESS_AFTER_ORDER_CREATE_ADD_PRODUCTS');
            $order->send_order_email($insert_id, 2);
            ipn_debug_email('Breakpoint: 5m - emailing customer');
            $zco_notifier->notify('NOTIFY_CHECKOUT_PROCESS_AFTER_SEND_ORDER_EMAIL');
            /** Prepare sales-tracking data for use by notifier class **/
            $ototal = $order_subtotal = $credits_applied = 0;
            for ($i=0, $n=sizeof($order_totals); $i<$n; $i++) {
                if ($order_totals[$i]['code'] == 'ot_subtotal') $order_subtotal = $order_totals[$i]['value'];
                if ($$order_totals[$i]['code']->credit_class == true) $credits_applied += $order_totals[$i]['value'];
                if ($order_totals[$i]['code'] == 'ot_total') $ototal = $order_totals[$i]['value'];
            }
            $commissionable_order = ($order_subtotal - $credits_applied);
            $commissionable_order_formatted = $currencies->format($commissionable_order);
            $_SESSION['order_summary']['order_number'] = $insert_id;
            $_SESSION['order_summary']['order_subtotal'] = $order_subtotal;
            $_SESSION['order_summary']['credits_applied'] = $credits_applied;
            $_SESSION['order_summary']['order_total'] = $ototal;
            $_SESSION['order_summary']['commissionable_order'] = $commissionable_order;
            $_SESSION['order_summary']['commissionable_order_formatted'] = $commissionable_order_formatted;
            $_SESSION['order_summary']['coupon_code'] = $order->info['coupon_code'];
            $zco_notifier->notify('NOTIFY_CHECKOUT_PROCESS_HANDLE_AFFILIATES', 'paypalipn');
            $_SESSION['cart']->reset(true);
            ipn_debug_email('Breakpoint: 5n - emptying cart');
            $ordersID = $insert_id;
            $paypalipnID = $pp_hist_id;
            ipn_debug_email('Breakpoint: 6 - Completed IPN order add.' . '    ordersID = '. $ordersID . '  IPN tracking record = ' . $paypalipnID);
            if (!($new_record_needed && $txn_type == 'echeck-cleared'))  break;
        }else{
            $insert_id = $order->create($order_totals);
            $zco_notifier->notify('NOTIFY_CHECKOUT_PROCESS_AFTER_ORDER_CREATE');
            ipn_debug_email('Breakpoint: 5a - built order -- OID: ' . $insert_id);
            $sql_data_array = ipn_create_order_array($insert_id, $txn_type);
            ipn_debug_email('Breakpoint: 5b - PP table OID: ' . print_r($sql_data_array, true));
            zen_db_perform(TABLE_PAYPAL, $sql_data_array);
            ipn_debug_email('Breakpoint: 5c - PP table OID saved');
            $pp_hist_id = $db->Insert_ID();
            $zco_notifier->notify('NOTIFY_CHECKOUT_PROCESS_AFTER_PAYMENT_MODULES_AFTER_ORDER_CREATE');
            ipn_debug_email('Breakpoint: 5d - PP hist ID: ' . $pp_hist_id);
            $sql_data_array = ipn_create_order_history_array($pp_hist_id);
            ipn_debug_email('Breakpoint: 5e - PP hist_data:' . print_r($sql_data_array, true));
            zen_db_perform(TABLE_PAYPAL_PAYMENT_STATUS_HISTORY, $sql_data_array);
            ipn_debug_email('Breakpoint: 5f - PP hist saved');
            $new_status = MODULE_PAYMENT_PAYPAL_ORDER_STATUS_ID;
            ipn_debug_email('Breakpoint: 5g - new status code: ' . $new_status);
            if ($_POST['payment_status'] =='Pending') {
              $new_status = (defined('MODULE_PAYMENT_PAYPAL_PROCESSING_STATUS_ID') && (int)MODULE_PAYMENT_PAYPAL_PROCESSING_STATUS_ID > 0 ? (int)MODULE_PAYMENT_PAYPAL_PROCESSING_STATUS_ID : 2);
              ipn_debug_email('Breakpoint: 5h - newer status code: ' . (int)$new_status);
              $sql = "UPDATE " . TABLE_ORDERS  . "
                      SET orders_status = " . (int)$new_status . "
                      WHERE orders_id = '" . (int)$insert_id . "'";
              $db->Execute($sql);
              ipn_debug_email('Breakpoint: 5i - order table updated');
            }
            $sql_data_array = array('orders_id' => (int)$insert_id,
                                    'orders_status_id' => (int)$new_status,
                                    'date_added' => 'now()',
                                    'comments' => 'PayPal status: ' . $_POST['payment_status'] . ' ' . $_POST['pending_reason']. ' @ '.$_POST['payment_date'] . (($_POST['parent_txn_id'] !='') ? "\n" . ' Parent Trans ID:' . $_POST['parent_txn_id'] : '') . "\n" . ' Trans ID:' . $_POST['txn_id'] . "\n" . ' Amount: ' . $_POST['mc_gross'] . ' ' . $_POST['mc_currency'],
                                    'customer_notified' => 0
                                    );
            ipn_debug_email('Breakpoint: 5j - order stat hist update:' . print_r($sql_data_array, true));
            zen_db_perform(TABLE_ORDERS_STATUS_HISTORY, $sql_data_array);
            if (MODULE_PAYMENT_PAYPAL_ADDRESS_OVERRIDE == '1') {
              $sql_data_array['comments'] = '**** ADDRESS OVERRIDE ALERT!!! **** CHECK PAYPAL ORDER DETAILS FOR ACTUAL ADDRESS SELECTED BY CUSTOMER!!';
              $sql_data_array['customer_notified'] = -1;
            }
            zen_db_perform(TABLE_ORDERS_STATUS_HISTORY, $sql_data_array);
            ipn_debug_email('Breakpoint: 5k - OSH update done');
            $order->create_add_products($insert_id, 2);
            ipn_debug_email('Breakpoint: 5L - adding products');
            $_SESSION['order_number_created'] = $insert_id;
            $zco_notifier->notify('NOTIFY_CHECKOUT_PROCESS_AFTER_ORDER_CREATE_ADD_PRODUCTS');
            $order->send_order_email($insert_id, 2);
            ipn_debug_email('Breakpoint: 5m - emailing customer');
            $zco_notifier->notify('NOTIFY_CHECKOUT_PROCESS_AFTER_SEND_ORDER_EMAIL');
            /** Prepare sales-tracking data for use by notifier class **/
            $ototal = $order_subtotal = $credits_applied = 0;
            for ($i=0, $n=sizeof($order_totals); $i<$n; $i++) {
              if ($order_totals[$i]['code'] == 'ot_subtotal') $order_subtotal = $order_totals[$i]['value'];
              if ($$order_totals[$i]['code']->credit_class == true) $credits_applied += $order_totals[$i]['value'];
              if ($order_totals[$i]['code'] == 'ot_total') $ototal = $order_totals[$i]['value'];
            }
            $commissionable_order = ($order_subtotal - $credits_applied);
            $commissionable_order_formatted = $currencies->format($commissionable_order);
            $_SESSION['order_summary']['order_number'] = $insert_id;
            $_SESSION['order_summary']['order_subtotal'] = $order_subtotal;
            $_SESSION['order_summary']['credits_applied'] = $credits_applied;
            $_SESSION['order_summary']['order_total'] = $ototal;
            $_SESSION['order_summary']['commissionable_order'] = $commissionable_order;
            $_SESSION['order_summary']['commissionable_order_formatted'] = $commissionable_order_formatted;
            $_SESSION['order_summary']['coupon_code'] = $order->info['coupon_code'];
            $zco_notifier->notify('NOTIFY_CHECKOUT_PROCESS_HANDLE_AFFILIATES', 'paypalipn');
            $_SESSION['cart']->reset(true);
            ipn_debug_email('Breakpoint: 5n - emptying cart');
            $ordersID = $insert_id;
            $paypalipnID = $pp_hist_id;
            ipn_debug_email('Breakpoint: 6 - Completed IPN order add.' . '    ordersID = '. $ordersID . '  IPN tracking record = ' . $paypalipnID);
            if (!($new_record_needed && $txn_type == 'echeck-cleared'))  break;
        }
    }
    case 'parent':
    case 'cleared-address':
    case 'cleared-multicurrency':
    case 'cleared-echeck':
    case 'cleared-authorization':
    case 'cleared-verify':
    case 'cleared-intl':
    case 'cleared-review':
    case 'echeck-denied':
    case 'echeck-cleared':
    case 'denied-address':
    case 'denied-multicurrency':
    case 'denied-echeck':
    case 'failed-echeck':
    case 'denied-intl':
    case 'denied':
    case 'voided':
    case 'express-checkout-cleared':
      ipn_debug_email('IPN NOTICE :: Storing order/update details for order #' . $ordersID . ' txn_id: ' . $_POST['txn_id'] . ' PP IPN ID: ' . $paypalipnID);
      if ($txn_type == 'parent') {
        $sql_data_array = ipn_create_order_array($ordersID, $txn_type);
        zen_db_perform(TABLE_PAYPAL, $sql_data_array);
        $paypalipnID = $db->Insert_ID();
      } else {
        $sql_data_array = ipn_create_order_update_array($txn_type);
        zen_db_perform(TABLE_PAYPAL, $sql_data_array, 'update', "txn_id='" . ($txn_type == 'cleared-authorization' ? $_POST['parent_txn_id'] : $_POST['txn_id']) . "'");
        $sql = "select paypal_ipn_id from " . TABLE_PAYPAL . " where txn_id='" . $_POST['txn_id'] . "'";
        $result = $db->Execute($sql);
        $paypalipnID = $result->fields['paypal_ipn_id'];
      }
      $sql_data_array = ipn_create_order_history_array($paypalipnID);
      zen_db_perform(TABLE_PAYPAL_PAYMENT_STATUS_HISTORY, $sql_data_array);
      ipn_debug_email('IPN NOTICE :: Added PP status-history record for order #' . $ordersID . ' txn_id: ' . $_POST['txn_id'] . ' (updated/child) PP IPN ID: ' . $paypalipnID);
 
      switch ($txn_type) {
        case 'voided':
        case ($_POST['payment_status'] == 'Refunded' || $_POST['payment_status'] == 'Reversed' || $_POST['payment_status'] == 'Voided'):
          //payment_status=Refunded or payment_status=Voided
          $new_status = MODULE_PAYMENT_PAYPALWPP_REFUNDED_STATUS_ID;
          if (defined('MODULE_PAYMENT_PAYPAL_REFUND_ORDER_STATUS_ID') && (int)MODULE_PAYMENT_PAYPAL_REFUND_ORDER_STATUS_ID > 0 && !$isECtransaction) $new_status = MODULE_PAYMENT_PAYPAL_REFUND_ORDER_STATUS_ID;
          break;
        case 'echeck-denied':
        case 'denied-echeck':
        case 'failed-echeck':
          //payment_status=Denied or failed
          $new_status = ($isECtransaction ? MODULE_PAYMENT_PAYPALWPP_REFUNDED_STATUS_ID : MODULE_PAYMENT_PAYPAL_REFUND_ORDER_STATUS_ID);
          break;
        case 'echeck-cleared':
          $new_status = (defined('MODULE_PAYMENT_PAYPAL_ORDER_STATUS_ID') ? MODULE_PAYMENT_PAYPAL_ORDER_STATUS_ID : 2);
          break;
        case ($txn_type=='express-checkout-cleared' || substr($txn_type,0,8) == 'cleared-'):
          //express-checkout-cleared
          $new_status = ($isECtransaction && defined('MODULE_PAYMENT_PAYPALWPP_ORDER_STATUS_ID') ? MODULE_PAYMENT_PAYPALWPP_ORDER_STATUS_ID : MODULE_PAYMENT_PAYPAL_ORDER_STATUS_ID);
          if ((int)$new_status == 0) $new_status = 2;
          break;
        case 'pending-auth':
          // pending authorization
          $new_status = ($isECtransaction ? MODULE_PAYMENT_PAYPALWPP_REFUNDED_STATUS_ID : MODULE_PAYMENT_PAYPAL_REFUND_ORDER_STATUS_ID);
          break;
        case (substr($txn_type,0,7) == 'denied-'):
          // denied for any other reason - treat as pending for now
        case (substr($txn_type,0,8) == 'pending-'):
          // pending anything
          $new_status = ($isECtransaction ? MODULE_PAYMENT_PAYPALWPP_ORDER_PENDING_STATUS_ID : MODULE_PAYMENT_PAYPAL_PROCESSING_STATUS_ID);
          break;
      }
      // update order status history with new information
      ipn_debug_email('IPN NOTICE :: Set new status ' . $new_status . " for order ID = " .  $ordersID . ($_POST['pending_reason'] != '' ? '.   Reason_code = ' . $_POST['pending_reason'] : '') );
      if ((int)$new_status == 0) $new_status = 1;
      if (in_array($_POST['payment_status'], array('Refunded', 'Reversed', 'Denied', 'Failed'))
           || substr($txn_type,0,8) == 'cleared-' || $txn_type=='echeck-cleared' || $txn_type == 'express-checkout-cleared') {
        ipn_update_orders_status_and_history($ordersID, $new_status, $txn_type);
        $zco_notifier->notify('NOTIFY_PAYPALIPN_STATUS_HISTORY_UPDATE', array($ordersID, $new_status, $txn_type));
      }
      break;
    default:
      // can't understand result found. Thus, logging and aborting.
      ipn_debug_email('IPN WARNING :: Could not process for txn type: ' . $txn_type . "\n" . ' postdata=' . str_replace('&', " \n&", urldecode(print_r($_POST, TRUE))));
  }
  // debug info only
  switch (TRUE) {
    case ($txn_type == 'pending-echeck' && (int)$ordersID > 0):
      ipn_debug_email('IPN NOTICE :: Pending echeck transaction for existing order. No action required. Waiting for echeck to clear.');
      break;
    case ($txn_type == 'pending-multicurrency' && (int)$ordersID > 0):
      ipn_debug_email('IPN NOTICE :: Pending multicurrency transaction for existing order. No action required. Waiting for merchant to "accept" the order via PayPal account console.');
      break;
    case ($txn_type == 'pending-address' && (int)$ordersID > 0):
      ipn_debug_email('IPN NOTICE :: "Pending address" transaction for existing order. No action required. Waiting for address approval by store owner via PayPal account console.');
      break;
    case ($txn_type == 'pending-paymentreview' && (int)$ordersID > 0):
      ipn_debug_email('IPN NOTICE :: "Pending payment review" transaction for existing order. No action required. Waiting for PayPal to complete their Payment Review. Do not ship order until review is completed.');
      break;
  }
}

9. 前面的所有流程完成之后,先生成订单后付款的功能就已经搞定了,接下来就是在后台修改为付款订单价格数量及运费的问题了。代码如下:
 

<?php
/**
 * @package admin
 * @copyright Copyright 2003-2010 Zen Cart Development Team
 * @copyright Portions Copyright 2003 osCommerce
 * @license http://www.zen-cart.com/license/2_0.txt GNU Public License V2.0
 * @version $Id: orders.php 15994 2010-04-19 17:17:51Z ajeh $
 */
 
  require('includes/application_top.php');
  
  require(DIR_WS_CLASSES . 'currencies.php');
  $currencies = new currencies();
 
  include(DIR_WS_CLASSES . 'order.php');
  
  //订单修改提交后的数据处理代码 EOF
  
  if(!empty($_POST['ot_total']) && isset($_GET[oID]) && $_GET[oID] !=''){
  
      $update_order_id=$_GET[oID];
      $products_list=array();
      $total_list=array();
      foreach($_POST['reference_oid'] as $value1){
          $products_list[$value1]=array();
      }
  
      $products_list_loop = $products_list;
  
      foreach($_POST as $key2=>$value2){
          foreach ($products_list_loop as $key3=>$value3){
              if($key3 == ltrim(strrchr($key2,'_'),'_')){
                  $array_key = substr($key2,0,strripos($key2,'_'));
                  if($array_key != 'qty'){
                      $products_list[$key3][$array_key] = $value2 / $_POST['currencies_value'];
                  }else{
                      $products_list[$key3][$array_key] = $value2;
                  }
              }
          }
      }
  
      $order_total_value=$_POST['ot_total'] / $_POST['currencies_value'];
      $order_total_text=$currencies->format($order_total_value,true,$_POST['currencies_key'],$_POST['currencies_value']);
  
      $order_subtotal_value=$_POST['ot_subtotal'] / $_POST['currencies_value'];
      $order_subtotal_text=$currencies->format($order_subtotal_value,true,$_POST['currencies_key'],$_POST['currencies_value']);
  
      $order_shipping_value=$_POST['ot_shipping'] / $_POST['currencies_value'];;
      $order_shipping_text=$currencies->format($order_shipping_value,true,$_POST['currencies_key'],$_POST['currencies_value']);
  
      //       $order_gv_text=$_POST['ot_gv'];
      //       $order_gv_value=$_POST['ot_gv'];
  
      //       $order_coupon_text=$_POST['ot_coupon'];
      //       $order_coupon_value=$_POST['ot_coupon'];
  
      foreach($products_list as $key4=>$value4){
          $sql_update_order_products="update " . TABLE_ORDERS_PRODUCTS . "
                                      set products_price = " . $products_list[$key4]['price_ex'] . " , final_price = " . $products_list[$key4]['price_ex'] . " , products_quantity = " . $products_list[$key4]['qty'] . "
                                      where orders_id =  " . $update_order_id . " and products_id =  " . $key4;
          $db->Execute($sql_update_order_products);
          //           echo "更新产品价格和数量: " . $sql_update_order_products . "<br />";
          //           var_dump($db->Execute($sql_update_order_products));
          //           echo '<br />';
      }
  
      if($order_subtotal_text){
          $sql_update_subtotal="update " . TABLE_ORDERS_TOTAL . "
                                   set text = '" . $order_subtotal_text . "' , value = " . $order_subtotal_value ."
                                   where orders_id = " . $update_order_id . " and class = 'ot_subtotal'";
          $db->Execute($sql_update_subtotal);
          //           echo "更新产品总价: " . $sql_update_subtotal . "<br />";
          //           var_dump($db->Execute($sql_update_subtotal));
          //           echo '<br />';
      }
  
      if($order_shipping_text){
          $sql_update_shipping="update " . TABLE_ORDERS_TOTAL . "
                                   set text = '" . $order_shipping_text . "' , value = " . $order_shipping_value ."
                                   where orders_id = " . $update_order_id . " and class = 'ot_shipping'";
          $db->Execute($sql_update_shipping);
          //           echo "更新运费价格: " . $sql_update_shipping . "<br />";
          //           var_dump($db->Execute($sql_update_shipping));
          //           echo '<br />';
      }
  
      if($order_total_text){
          $sql_update_total="update " . TABLE_ORDERS_TOTAL . "
                                   set text = '" . $order_total_text . "' , value = " . $order_total_value ."
                                   where orders_id = " . $update_order_id . " and class = 'ot_total'";
          $db->Execute($sql_update_total);
          //           echo "更新订单总价: " . $sql_update_total . "<br />";
          //           var_dump($db->Execute($sql_update_total));
          //           echo '<br />';
  
          $sql_update_order="update " . TABLE_ORDERS . " set order_total = " .$order_total_value . " where orders_id = " . $update_order_id;
          $db->Execute($sql_update_order);
          //           echo "更新订单: " . $sql_update_order . '<br />';
          //           var_dump($db->Execute($sql_update_order));
          //           echo '<br />';
      }
  
      echo "<script language=JavaScript> location.replace(location.href);</script>";
      //       echo '<pre>';
      //       echo "汇率: ".$_POST['currencies_value'] . '<br />';
      //       echo "转成默认货币:" . $order_total_value / $_POST['currencies_value'] . '<br />';
      //       echo '<br />';
      //       echo "交易货币值: ".$order_total_value."<br />";
      //       echo "转成交易货币样式: " . $currencies->format(($order_total_value / $_POST['currencies_value']),true,$_POST['currencies_key'],$_POST['currencies_value']);
      //       print_r($products_list);
      //       print_r($_POST);
      //       echo '</pre>';
  }
  
  //订单修改提交后的数据处理代码 BOF
  
  // prepare order-status pulldown list
  $orders_statuses = array();
  $orders_status_array = array();
  $orders_status = $db->Execute("select orders_status_id, orders_status_name
                                 from " . TABLE_ORDERS_STATUS . "
                                 where language_id = '" . (int)$_SESSION['languages_id'] . "' order by orders_status_id");
  while (!$orders_status->EOF) {
    $orders_statuses[] = array('id' => $orders_status->fields['orders_status_id'],
                               'text' => $orders_status->fields['orders_status_name'] . ' [' . $orders_status->fields['orders_status_id'] . ']');
    $orders_status_array[$orders_status->fields['orders_status_id']] = $orders_status->fields['orders_status_name'];
    $orders_status->MoveNext();
  }
 
  $action = (isset($_GET['action']) ? $_GET['action'] : '');
  $order_exists = false;
  if (isset($_GET['oID']) && trim($_GET['oID']) == '') unset($_GET['oID']);
  if ($action == 'edit' && !isset($_GET['oID'])) $action = '';
 
  if (isset($_GET['oID'])) {
    $oID = zen_db_prepare_input(trim($_GET['oID']));
 
    $orders = $db->Execute("select orders_id from " . TABLE_ORDERS . "
                            where orders_id = '" . $oID . "'");
    $order_exists = true;
    if ($orders->RecordCount() <= 0) {
      $order_exists = false;
      if ($action != '') $messageStack->add_session(ERROR_ORDER_DOES_NOT_EXIST . ' ' . $oID, 'error');
      zen_redirect(zen_href_link(FILENAME_ORDERS, zen_get_all_get_params(array('oID', 'action')), 'NONSSL'));
    }
  }
 
  if (zen_not_null($action) && $order_exists == true) {
    switch ($action) {
      case 'edit':
      // reset single download to on
        if ($_GET['download_reset_on'] > 0) {
          // adjust download_maxdays based on current date
          $check_status = $db->Execute("select customers_name, customers_email_address, orders_status,orders_num,
                                      date_purchased from " . TABLE_ORDERS . "
                                      where orders_id = '" . $_GET['oID'] . "'");
          $zc_max_days = zen_date_diff($check_status->fields['date_purchased'], date('Y-m-d H:i:s', time())) + DOWNLOAD_MAX_DAYS;
 
          $update_downloads_query = "update " . TABLE_ORDERS_PRODUCTS_DOWNLOAD . " set download_maxdays='" . $zc_max_days . "', download_count='" . DOWNLOAD_MAX_COUNT . "' where orders_id='" . $_GET['oID'] . "' and orders_products_download_id='" . $_GET['download_reset_on'] . "'";
          $db->Execute($update_downloads_query);
          unset($_GET['download_reset_on']);
 
          $messageStack->add_session(SUCCESS_ORDER_UPDATED_DOWNLOAD_ON, 'success');
          zen_redirect(zen_href_link(FILENAME_ORDERS, zen_get_all_get_params(array('action')) . 'action=edit', 'NONSSL'));
        }
      // reset single download to off
        if ($_GET['download_reset_off'] > 0) {
          // adjust download_maxdays based on current date
          // *** fix: adjust count not maxdays to cancel download
//          $update_downloads_query = "update " . TABLE_ORDERS_PRODUCTS_DOWNLOAD . " set download_maxdays='0', download_count='0' where orders_id='" . $_GET['oID'] . "' and orders_products_download_id='" . $_GET['download_reset_off'] . "'";
          $update_downloads_query = "update " . TABLE_ORDERS_PRODUCTS_DOWNLOAD . " set download_count='0' where orders_id='" . $_GET['oID'] . "' and orders_products_download_id='" . $_GET['download_reset_off'] . "'";
          unset($_GET['download_reset_off']);
          $db->Execute($update_downloads_query);
 
          $messageStack->add_session(SUCCESS_ORDER_UPDATED_DOWNLOAD_OFF, 'success');
          zen_redirect(zen_href_link(FILENAME_ORDERS, zen_get_all_get_params(array('action')) . 'action=edit', 'NONSSL'));
        }
      break;
      case 'update_order':
        // demo active test
        if (zen_admin_demo()) {
          $_GET['action']= '';
          $messageStack->add_session(ERROR_ADMIN_DEMO, 'caution');
          zen_redirect(zen_href_link(FILENAME_ORDERS, zen_get_all_get_params(array('action')) . 'action=edit', 'NONSSL'));
        }
        $oID = zen_db_prepare_input($_GET['oID']);
        $status = zen_db_prepare_input($_POST['status']);
        $comments = zen_db_prepare_input($_POST['comments']);
        $tracking_number = zen_db_prepare_input($_POST['tracking_number']);
 
        $order_updated = false;
        $check_status = $db->Execute("select customers_name, customers_email_address, orders_status,orders_num,tracking_number,
                                      date_purchased from " . TABLE_ORDERS . "
                                      where orders_id = '" . $oID . "'");
 
        if ( ($check_status->fields['orders_status'] != $status) || zen_not_null($comments)) {
          $db->Execute("update " . TABLE_ORDERS . "
                        set orders_status = '" . zen_db_input($status) . "', last_modified = now(), tracking_number = '" . zen_db_input($tracking_number) . "'
                        where orders_id = '" . $oID . "'");
 
          $customer_notified = '0';
          if (isset($_POST['notify']) && ($_POST['notify'] == '1')) {
 
            $notify_comments = '';
            if (isset($_POST['notify_comments']) && ($_POST['notify_comments'] == 'on') && zen_not_null($comments)) {
              $notify_comments = EMAIL_TEXT_COMMENTS_UPDATE . $comments . "\n\n";
            }
            //send emails
            $message =
            EMAIL_TEXT_ORDER_NUMBER . ' ' . $check_status->fields['orders_num'] . "\n\n" .
            EMAIL_TEXT_INVOICE_URL . ' ' . zen_catalog_href_link(FILENAME_CATALOG_ACCOUNT_HISTORY_INFO, 'order_id=' . $oID, 'SSL') . "\n\n" .
            EMAIL_TEXT_DATE_ORDERED . ' ' . zen_date_long($check_status->fields['date_purchased']) . "\n\n" .
            strip_tags($notify_comments) .
            EMAIL_TEXT_STATUS_UPDATED . sprintf(EMAIL_TEXT_STATUS_LABEL, $orders_status_array[$status] ) .
            EMAIL_TEXT_STATUS_PLEASE_REPLY;
 
            $html_msg['EMAIL_CUSTOMERS_NAME']    = $check_status->fields['customers_name'];
            $html_msg['EMAIL_TEXT_ORDER_NUMBER'] = EMAIL_TEXT_ORDER_NUMBER . ' ' . $check_status->fields['orders_num'];
            $html_msg['EMAIL_TEXT_INVOICE_URL']  = '<a href="' . zen_catalog_href_link(FILENAME_CATALOG_ACCOUNT_HISTORY_INFO, 'order_id=' . $oID, 'SSL') .'">'.str_replace(':','',EMAIL_TEXT_INVOICE_URL).'</a>';
            $html_msg['EMAIL_TEXT_DATE_ORDERED'] = EMAIL_TEXT_DATE_ORDERED . ' ' . zen_date_long($check_status->fields['date_purchased']);
            $html_msg['EMAIL_TEXT_STATUS_COMMENTS'] = nl2br($notify_comments);
            $html_msg['EMAIL_TEXT_STATUS_UPDATED'] = str_replace('\n','', EMAIL_TEXT_STATUS_UPDATED);
            $html_msg['EMAIL_TEXT_STATUS_LABEL'] = str_replace('\n','', sprintf(EMAIL_TEXT_STATUS_LABEL, $orders_status_array[$status] ));
            $html_msg['EMAIL_TEXT_NEW_STATUS'] = $orders_status_array[$status];
            $html_msg['EMAIL_TEXT_STATUS_PLEASE_REPLY'] = str_replace('\n','', EMAIL_TEXT_STATUS_PLEASE_REPLY);
 
            zen_mail($check_status->fields['customers_name'], $check_status->fields['customers_email_address'], EMAIL_TEXT_SUBJECT . ' #' . $check_status->fields['orders_num'], $message, STORE_NAME, EMAIL_FROM, $html_msg, 'order_status');
            $customer_notified = '1';
 
            //send extra emails
            if (SEND_EXTRA_ORDERS_STATUS_ADMIN_EMAILS_TO_STATUS == '1' and SEND_EXTRA_ORDERS_STATUS_ADMIN_EMAILS_TO != '') {
              zen_mail('', SEND_EXTRA_ORDERS_STATUS_ADMIN_EMAILS_TO, SEND_EXTRA_ORDERS_STATUS_ADMIN_EMAILS_TO_SUBJECT . ' ' . EMAIL_TEXT_SUBJECT . ' #' . $check_status->fields['orders_num'], $message, STORE_NAME, EMAIL_FROM, $html_msg, 'order_status_extra');
            }
          } elseif (isset($_POST['notify']) && ($_POST['notify'] == '-1')) {
            // hide comment
            $customer_notified = '-1';
          }
 
          $db->Execute("insert into " . TABLE_ORDERS_STATUS_HISTORY . "
                      (orders_id, orders_status_id, date_added, customer_notified, comments)
                      values ('" . $oID . "',
                      '" . zen_db_input($status) . "',
                      now(),
                      '" . zen_db_input($customer_notified) . "',
                      '" . zen_db_input($comments)  . "')");
          $order_updated = true;
        }
 
        // trigger any appropriate updates which should be sent back to the payment gateway:
        $order = new order($oID);
        if ($order->info['payment_module_code']) {
          if (file_exists(DIR_FS_CATALOG_MODULES . 'payment/' . $order->info['payment_module_code'] . '.php')) {
            require_once(DIR_FS_CATALOG_MODULES . 'payment/' . $order->info['payment_module_code'] . '.php');
            require_once(DIR_FS_CATALOG_LANGUAGES . $_SESSION['language'] . '/modules/payment/' . $order->info['payment_module_code'] . '.php');
            $module = new $order->info['payment_module_code'];
            if (method_exists($module, '_doStatusUpdate')) {
              $response = $module->_doStatusUpdate($oID, $status, $comments, $customer_notified, $check_status->fields['orders_status']);
            }
          }
        }
 
        if ($order_updated == true) {
         if ($status == DOWNLOADS_ORDERS_STATUS_UPDATED_VALUE) {
            // adjust download_maxdays based on current date
            $zc_max_days = zen_date_diff($check_status->fields['date_purchased'], date('Y-m-d H:i:s', time())) + DOWNLOAD_MAX_DAYS;
 
            $update_downloads_query = "update " . TABLE_ORDERS_PRODUCTS_DOWNLOAD . " set download_maxdays='" . $zc_max_days . "', download_count='" . DOWNLOAD_MAX_COUNT . "' where orders_id='" . $oID . "'";
            $db->Execute($update_downloads_query);
          }
          $messageStack->add_session(SUCCESS_ORDER_UPDATED, 'success');
        } else {
          $messageStack->add_session(WARNING_ORDER_NOT_UPDATED, 'warning');
        }
        zen_redirect(zen_href_link(FILENAME_ORDERS, zen_get_all_get_params(array('action')) . 'action=edit', 'NONSSL'));
        break;
      case 'deleteconfirm':
        // demo active test
        if (zen_admin_demo()) {
          $_GET['action']= '';
          $messageStack->add_session(ERROR_ADMIN_DEMO, 'caution');
          zen_redirect(zen_href_link(FILENAME_ORDERS, zen_get_all_get_params(array('oID', 'action')), 'NONSSL'));
        }
        $oID = zen_db_prepare_input($_GET['oID']);
 
        zen_remove_order($oID, $_POST['restock']);
 
        zen_redirect(zen_href_link(FILENAME_ORDERS, zen_get_all_get_params(array('oID', 'action')), 'NONSSL'));
        break;
      case 'delete_cvv':
        $delete_cvv = $db->Execute("update " . TABLE_ORDERS . " set cc_cvv = '" . TEXT_DELETE_CVV_REPLACEMENT . "' where orders_id = '" . (int)$_GET['oID'] . "'");
        zen_redirect(zen_href_link(FILENAME_ORDERS, zen_get_all_get_params(array('action')) . 'action=edit', 'NONSSL'));
        break;
      case 'mask_cc':
        $result  = $db->Execute("select cc_number from " . TABLE_ORDERS . " where orders_id = '" . (int)$_GET['oID'] . "'");
        $old_num = $result->fields['cc_number'];
        $new_num = substr($old_num, 0, 4) . str_repeat('*', (strlen($old_num) - 8)) . substr($old_num, -4);
        $mask_cc = $db->Execute("update " . TABLE_ORDERS . " set cc_number = '" . $new_num . "' where orders_id = '" . (int)$_GET['oID'] . "'");
        zen_redirect(zen_href_link(FILENAME_ORDERS, zen_get_all_get_params(array('action')) . 'action=edit', 'NONSSL'));
        break;
 
      case 'doRefund':
        $order = new order($oID);
        if ($order->info['payment_module_code']) {
          if (file_exists(DIR_FS_CATALOG_MODULES . 'payment/' . $order->info['payment_module_code'] . '.php')) {
            require_once(DIR_FS_CATALOG_MODULES . 'payment/' . $order->info['payment_module_code'] . '.php');
            require_once(DIR_FS_CATALOG_LANGUAGES . $_SESSION['language'] . '/modules/payment/' . $order->info['payment_module_code'] . '.php');
            $module = new $order->info['payment_module_code'];
            if (method_exists($module, '_doRefund')) {
              $module->_doRefund($oID);
            }
          }
        }
        zen_redirect(zen_href_link(FILENAME_ORDERS, zen_get_all_get_params(array('action')) . 'action=edit', 'NONSSL'));
        break;
      case 'doAuth':
        $order = new order($oID);
        if ($order->info['payment_module_code']) {
          if (file_exists(DIR_FS_CATALOG_MODULES . 'payment/' . $order->info['payment_module_code'] . '.php')) {
            require_once(DIR_FS_CATALOG_MODULES . 'payment/' . $order->info['payment_module_code'] . '.php');
            require_once(DIR_FS_CATALOG_LANGUAGES . $_SESSION['language'] . '/modules/payment/' . $order->info['payment_module_code'] . '.php');
            $module = new $order->info['payment_module_code'];
            if (method_exists($module, '_doAuth')) {
              $module->_doAuth($oID, $order->info['total'], $order->info['currency']);
            }
          }
        }
        zen_redirect(zen_href_link(FILENAME_ORDERS, zen_get_all_get_params(array('action')) . 'action=edit', 'NONSSL'));
        break;
      case 'doCapture':
        $order = new order($oID);
        if ($order->info['payment_module_code']) {
          if (file_exists(DIR_FS_CATALOG_MODULES . 'payment/' . $order->info['payment_module_code'] . '.php')) {
            require_once(DIR_FS_CATALOG_MODULES . 'payment/' . $order->info['payment_module_code'] . '.php');
            require_once(DIR_FS_CATALOG_LANGUAGES . $_SESSION['language'] . '/modules/payment/' . $order->info['payment_module_code'] . '.php');
            $module = new $order->info['payment_module_code'];
            if (method_exists($module, '_doCapt')) {
              $module->_doCapt($oID, 'Complete', $order->info['total'], $order->info['currency']);
            }
          }
        }
        zen_redirect(zen_href_link(FILENAME_ORDERS, zen_get_all_get_params(array('action')) . 'action=edit', 'NONSSL'));
        break;
      case 'doVoid':
        $order = new order($oID);
        if ($order->info['payment_module_code']) {
          if (file_exists(DIR_FS_CATALOG_MODULES . 'payment/' . $order->info['payment_module_code'] . '.php')) {
            require_once(DIR_FS_CATALOG_MODULES . 'payment/' . $order->info['payment_module_code'] . '.php');
            require_once(DIR_FS_CATALOG_LANGUAGES . $_SESSION['language'] . '/modules/payment/' . $order->info['payment_module_code'] . '.php');
            $module = new $order->info['payment_module_code'];
            if (method_exists($module, '_doVoid')) {
              $module->_doVoid($oID);
            }
          }
        }
        zen_redirect(zen_href_link(FILENAME_ORDERS, zen_get_all_get_params(array('action')) . 'action=edit', 'NONSSL'));
        break;
    }
  }
?>
<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN">
<html <?php echo HTML_PARAMS; ?>>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=<?php echo CHARSET; ?>">
<title><?php echo TITLE; ?></title>
<link rel="stylesheet" type="text/css" href="includes/stylesheet.css">
<link rel="stylesheet" type="text/css" media="print" href="includes/stylesheet_print.css">
<link rel="stylesheet" type="text/css" href="includes/cssjsmenuhover.css" media="all" id="hoverJS">
<script language="javascript" src="includes/menu.js"></script>
<script language="javascript" src="includes/general.js"></script>
<script type="text/javascript">
  <!--
  function init()
  {
    cssjsmenu('navbar');
    if (document.getElementById)
    {
      var kill = document.getElementById('hoverJS');
      kill.disabled = true;
    }
  }
  // -->
</script>
<script language="javascript" type="text/javascript"><!--
function couponpopupWindow(url) {
  window.open(url,'popupWindow','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=yes,copyhistory=no,width=450,height=280,screenX=150,screenY=150,top=150,left=150')
}
//--></script>
<link rel="stylesheet" type="text/css" href="includes/javascript/spiffyCal/spiffyCal_v2_1.css">
<script language="JavaScript" src="includes/javascript/spiffyCal/spiffyCal_v2_1.js"></script>
 
<?php //引入一个jquery库,然后就是控制修改价格的Jquery代码 EOF ?>
<script language="JavaScript" src="includes/javascript/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
    $("#orders_edit").click(function(){
      $("#orders_submit").show();
      $("#orders_reset").show();
      $("#orders_edit").hide();
      $("#products_list_changes").show();
      $("#products_list_default").hide();
    });
    
    $("#orders_reset").click(function(){
      location.replace(location.href);
    });
    
    $("#orders_submit").click(function(){
        if($("input[name='ot_total']").val()<0){
            alert("总价格为负数,这不符合规定");
            return false;  
        }
    });
  
    $("#products_list_changes input").keypress(function(event) {  
      var keyCode = event.which;  
      if (keyCode == 46 || (keyCode >= 48 && keyCode <=57) || keyCode == 8) 
          return true;  
      else  
          return false;  
    }).focus(function() {  
      this.style.imeMode='disabled';  
    }); 
});
 
function init()
{
cssjsmenu('navbar');
if (document.getElementById)
{
  var kill = document.getElementById('hoverJS');
  kill.disabled = true;
}
}
 
function selectAll(){
  var checklist = document.getElementsByName ("order_id[]");
    if(document.getElementById("select_all").checked)
    {
    for(var i=0;i<checklist.length;i++)
    {
       checklist[i].checked = 1;
    }
  }else{
   for(var j=0;j<checklist.length;j++)
   {
      checklist[j].checked = 0;
   }
 }
}
  
//加法运算
function accAdd(arg1,arg2){
    var r1,r2,m;
    try{r1=arg1.toString().split(".")[1].length}catch(e){r1=0}
    try{r2=arg2.toString().split(".")[1].length}catch(e){r2=0}
    m=Math.pow(10,Math.max(r1,r2))
    return ((arg1*m+arg2*m)/m).toFixed(2);
  } 
 
//减法运算
function accSub(arg1, arg2) {
    var r1, r2, m, n;
    try { r1 = arg1.toString().split(".")[1].length } catch (e) { r1 = 0 }
    try { r2 = arg2.toString().split(".")[1].length } catch (e) { r2 = 0 }
    m = Math.pow(10, Math.max(r1, r2));
    n = (r1 >= r2) ? r1 : r2;
    return ((arg1 * m - arg2 * m) / m).toFixed(n);
  }
 
//乘法运算
function accMul(arg1,arg2)
{
  var m=0,s1=arg1.toString(),s2=arg2.toString();
  try{m+=s1.split(".")[1].length}catch(e){}
  try{m+=s2.split(".")[1].length}catch(e){}
  return Number(s1.replace(".",""))*Number(s2.replace(".",""))/Math.pow(10,m)
 
//除法运算
function accDiv(arg1, arg2) {
    var t1 = 0, t2 = 0, r1, r2;
    try { t1 = arg1.toString().split(".")[1].length } catch (e) { }
    try { t2 = arg2.toString().split(".")[1].length } catch (e) { }
    with (Math) {
        r1 = Number(arg1.toString().replace(".", ""))
        r2 = Number(arg2.toString().replace(".", ""))
        return (r1 / r2) * pow(10, t2 - t1);
    }
  }
 
function change_price_ex(order_id,final_price){
    var products_qty_simple = "qty_"+order_id;
    var products_qty = $("input[name='"+products_qty_simple+"']").val();
    var price_ex_value_simple = "price_ex_"+order_id;
    var price_ex_value = $("input[name='"+price_ex_value_simple+"']").val();
    
    if(isNaN(price_ex_value)){
        alert("你输入的不是数字,价格将恢复到原始值,请重新输入正确的价格。");
        $("input[name='"+price_ex_value_simple+"']").val(final_price);
        var price_ex_value = $("input[name='"+price_ex_value_simple+"']").val();
    }else{
        var numindex = parseInt(price_ex_value.indexOf("."),10);
        if(numindex > 0){
            var head = price_ex_value.substring(0,numindex);
            var bottom = price_ex_value.substring(numindex,numindex+3);
            var fianlNum = head+bottom;
            $("input[name='"+price_ex_value_simple+"']").val(fianlNum);
            var price_ex_value = fianlNum;
        }
    }
    var total_ex_value = (accMul(price_ex_value,products_qty)).toFixed(2);
    var total_ex = "total_ex_"+order_id;
    var total_ex_hidden = "total_ex_hidden_"+order_id;
    var price_inc = "price_inc_"+order_id;
    var total_inc = "total_inc_"+order_id;
    $("input[name='"+total_ex+"']").val(total_ex_value);
    $("#"+total_ex_hidden).text(total_ex_value);
    $("input[name='"+price_inc+"']").val(price_ex_value);
    $("input[name='"+total_inc+"']").val(total_ex_value);
    
    var str=0;
    $("#price_total p").each(function (i){
        str =  accAdd(str,parseFloat($(this).text()));
    })
    
    $("input[name='ot_subtotal']").val(str);
 
    var ot_subtotal = parseFloat($("input[name='ot_subtotal']").val());
    var ot_coupon = $("input[name='ot_coupon']").val();
    if(ot_coupon==undefined){
        ot_coupon=0;
    }
    var ot_gv = $("input[name='ot_gv']").val();
    if(ot_gv==undefined){
        ot_gv=0;
    }
    var ot_shipping = parseFloat($("input[name='ot_shipping']").val());
    var ot_total = accSub(accSub(accAdd(ot_subtotal,ot_shipping),ot_coupon),ot_gv);
    $("input[name='ot_total']").val(ot_total);
}
 
function change_qty(order_id){
    var products_qty_simple = "qty_"+order_id;
    var products_qty = parseInt($("input[name='"+products_qty_simple+"']").val());
    if(isNaN(products_qty) || products_qty==0){
        products_qty="";
    }
    var price_ex_value_simple = "price_ex_"+order_id;
    var price_ex_value = $("input[name='"+price_ex_value_simple+"']").val();
    $("input[name='"+products_qty_simple+"']").val(products_qty);
    
    var total_ex_value = (accMul(price_ex_value,products_qty)).toFixed(2);
    var total_ex = "total_ex_"+order_id;
    var total_ex_hidden = "total_ex_hidden_"+order_id;
    var price_inc = "price_inc_"+order_id;
    var total_inc = "total_inc_"+order_id;
    $("input[name='"+total_ex+"']").val(total_ex_value);
    $("#"+total_ex_hidden).text(total_ex_value);
    $("input[name='"+total_inc+"']").val(total_ex_value);
    
    var str=0;
    $("#price_total p").each(function (i){
        str =  accAdd(str,parseFloat($(this).text()));
    })
    
    $("input[name='ot_subtotal']").val(str);
 
    var ot_subtotal = parseFloat($("input[name='ot_subtotal']").val());
    var ot_coupon = $("input[name='ot_coupon']").val();
    if(ot_coupon==undefined){
        ot_coupon=0;
    }
    var ot_gv = $("input[name='ot_gv']").val();
    if(ot_gv==undefined){
        ot_gv=0;
    }
    var ot_shipping = parseFloat($("input[name='ot_shipping']").val());
    var ot_total = accSub(accSub(accAdd(ot_subtotal,ot_shipping),ot_coupon),ot_gv);
    $("input[name='ot_total']").val(ot_total);
}
 
function change_shipping(shipping_total){
    var ot_shipping = $("input[name='ot_shipping']").val();
    if(isNaN(ot_shipping)){
        alert("你输入的不是数字,运费将恢复到原始值,请重新输入正确的运费。");
        $("input[name='ot_shipping']").val(shipping_total);
        var ot_shipping = parseFloat($("input[name='ot_shipping']").val());
    }else{
        var numindex = parseInt(ot_shipping.indexOf("."),10);
        if(numindex > 0){
            var head = ot_shipping.substring(0,numindex);
            var bottom = ot_shipping.substring(numindex,numindex+3);
            var fianlNum = head+bottom;
            $("input[name='ot_shipping']").val(fianlNum);
            var ot_shipping = fianlNum;
        }
    }
    var ot_subtotal = parseFloat($("input[name='ot_subtotal']").val());
    var ot_coupon = $("input[name='ot_coupon']").val();
    if(ot_coupon==undefined){
        ot_coupon=0;
    }
    var ot_gv = $("input[name='ot_gv']").val();
    if(ot_gv==undefined){
        ot_gv=0;
    }
    var ot_total = accSub(accSub(accAdd(ot_subtotal,ot_shipping),ot_coupon),ot_gv);
    $("input[name='ot_total']").val(ot_total);
}
 
function price_ex_onlive(order_id,final_price){
    var products_qty_simple = "qty_"+order_id;
    var products_qty = $("input[name='"+products_qty_simple+"']").val();
    var price_ex_value_simple = "price_ex_"+order_id;
    var price_ex_value = $("input[name='"+price_ex_value_simple+"']").val();
    
    if(price_ex_value==""){
        alert("你输入的不是数字,价格将恢复到原始值,请重新输入正确的价格。");
        $("input[name='"+price_ex_value_simple+"']").val(final_price);
        var price_ex_value = $("input[name='"+price_ex_value_simple+"']").val();
    }
    var total_ex_value = (accMul(price_ex_value,products_qty)).toFixed(2);
    var total_ex = "total_ex_"+order_id;
    var total_ex_hidden = "total_ex_hidden_"+order_id;
    var price_inc = "price_inc_"+order_id;
    var total_inc = "total_inc_"+order_id;
    $("input[name='"+total_ex+"']").val(total_ex_value);
    $("#"+total_ex_hidden).text(total_ex_value);
    $("input[name='"+price_inc+"']").val(price_ex_value);
    $("input[name='"+total_inc+"']").val(total_ex_value);
    
    var str=0;
    $("#price_total p").each(function (i){
        str =  accAdd(str,parseFloat($(this).text()));
    })
    
    $("input[name='ot_subtotal']").val(str);
 
    var ot_subtotal = parseFloat($("input[name='ot_subtotal']").val());
    var ot_coupon = $("input[name='ot_coupon']").val();
    if(ot_coupon==undefined){
        ot_coupon=0;
    }
    var ot_gv = $("input[name='ot_gv']").val();
    if(ot_gv==undefined){
        ot_gv=0;
    }
    var ot_shipping = parseFloat($("input[name='ot_shipping']").val());
    var ot_total = accSub(accSub(accAdd(ot_subtotal,ot_shipping),ot_coupon),ot_gv);
    $("input[name='ot_total']").val(ot_total);
}
 
function qty_onlive(order_id,qty){
    var products_qty_simple = "qty_"+order_id;
    var products_qty = parseInt($("input[name='"+products_qty_simple+"']").val());
    if(isNaN(products_qty) || products_qty==0){
        alert("你输入的不是数字,数量将恢复到原始值,请重新输入正确的数量。");
        products_qty=qty;
    }
    var price_ex_value_simple = "price_ex_"+order_id;
    var price_ex_value = $("input[name='"+price_ex_value_simple+"']").val();
    $("input[name='"+products_qty_simple+"']").val(products_qty);
    
    var total_ex_value = (accMul(price_ex_value,products_qty)).toFixed(2);
    var total_ex = "total_ex_"+order_id;
    var total_ex_hidden = "total_ex_hidden_"+order_id;
    var price_inc = "price_inc_"+order_id;
    var total_inc = "total_inc_"+order_id;
    $("input[name='"+total_ex+"']").val(total_ex_value);
    $("#"+total_ex_hidden).text(total_ex_value);
    $("input[name='"+total_inc+"']").val(total_ex_value);
    
    var str=0;
    $("#price_total p").each(function (i){
        str =  accAdd(str,parseFloat($(this).text()));
    })
    
    $("input[name='ot_subtotal']").val(str);
 
    var ot_subtotal = parseFloat($("input[name='ot_subtotal']").val());
    var ot_coupon = $("input[name='ot_coupon']").val();
    if(ot_coupon==undefined){
        ot_coupon=0;
    }
    var ot_gv = $("input[name='ot_gv']").val();
    if(ot_gv==undefined){
        ot_gv=0;
    }
    var ot_shipping = parseFloat($("input[name='ot_shipping']").val());
    var ot_total = accSub(accSub(accAdd(ot_subtotal,ot_shipping),ot_coupon),ot_gv);
    $("input[name='ot_total']").val(ot_total);
}
 
function shipping_onlive(shipping_total){
    var ot_shipping = $("input[name='ot_shipping']").val();
    if(ot_shipping==""){
        alert("你输入的不是数字,运费将恢复到原始值,请重新输入正确的运费。");
        $("input[name='ot_shipping']").val(shipping_total);
        var ot_shipping = parseFloat($("input[name='ot_shipping']").val());
    }
    var ot_subtotal = parseFloat($("input[name='ot_subtotal']").val());
    var ot_coupon = $("input[name='ot_coupon']").val();
    if(ot_coupon==undefined){
        ot_coupon=0;
    }
    var ot_gv = $("input[name='ot_gv']").val();
    if(ot_gv==undefined){
        ot_gv=0;
    }
    var ot_total = accSub(accSub(accAdd(ot_subtotal,ot_shipping),ot_coupon),ot_gv);
    $("input[name='ot_total']").val(ot_total);
}
 
<?php //引入一个jquery库,然后就是控制修改价格的Jquery代码 BOF ?>
 
</script>
</head>
<body onLoad="init()">
<div id="spiffycalendar" class="text"></div>
<!-- header //-->
<div class="header-area">
<?php
  require(DIR_WS_INCLUDES . 'header.php');
?>
</div>
<!-- header_eof //-->
 
<!-- body //-->
<table border="0" width="100%" cellspacing="2" cellpadding="2">
  <tr>
<!-- body_text //-->
 
<?php if ($action == '') { ?>
<!-- search -->
    <td width="100%" valign="top"><table border="0" width="100%" cellspacing="0" cellpadding="2">
      <tr>
        <td><table border="0" width="100%" cellspacing="0" cellpadding="0">
         <tr><?php echo zen_draw_form('search', FILENAME_ORDERS, '', 'get', '', true); ?>
            <td width="65%" class="pageHeading" align="right"><?php echo zen_draw_separator('pixel_trans.gif', 1, HEADING_IMAGE_HEIGHT); ?></td>
            <td colspan="2" class="smallText" align="right">
<?php
// show reset search
  if ((isset($_GET['search']) && zen_not_null($_GET['search'])) or $_GET['cID'] !='' or isset($_GET['start']) or isset($_GET['end'])) {
    echo '<a href="' . zen_href_link(FILENAME_ORDERS, '', 'NONSSL') . '">' . zen_image_button('button_reset.gif', IMAGE_RESET) . '</a><br />';
  }
?>
<?php
  echo  'Search by orders num or Customer Information:' . zen_draw_input_field('search') . zen_hide_session_id();
  if (isset($_GET['search']) && zen_not_null($_GET['search'])) {
    $keywords = zen_db_input(zen_db_prepare_input($_GET['search']));
    echo '<br/ >' . TEXT_INFO_SEARCH_DETAIL_FILTER . $keywords;
  }
?>
            </td>
          </form>
 
 
         <?php echo zen_draw_form('search_orders_products', FILENAME_ORDERS, '', 'get', '', true); ?>
            <td class="pageHeading" align="right"><?php echo zen_draw_separator('pixel_trans.gif', 1, HEADING_IMAGE_HEIGHT); ?></td>
            <td colspan="2" class="smallText" align="right">
<?php
// show reset search orders_products
  if ((isset($_GET['search_orders_products']) && zen_not_null($_GET['search_orders_products'])) or $_GET['cID'] !='') {
    echo '<a href="' . zen_href_link(FILENAME_ORDERS, '', 'NONSSL') . '">' . zen_image_button('button_reset.gif', IMAGE_RESET) . '</a><br />';
  }
?>
<?php
  echo HEADING_TITLE_SEARCH_DETAIL_ORDERS_PRODUCTS . ' ' . zen_draw_input_field('search_orders_products') . zen_hide_session_id();
  if (isset($_GET['search_orders_products']) && zen_not_null($_GET['search_orders_products'])) {
    $keywords_orders_products = zen_db_input(zen_db_prepare_input($_GET['search_orders_products']));
    echo '<br/ >' . TEXT_INFO_SEARCH_DETAIL_FILTER_ORDERS_PRODUCTS . zen_db_prepare_input($keywords_orders_products);
  }
?>
            </td>
          </form>
 
        </table></td>
      </tr>
      <tr>
          <td width="100%">
              <table  cellspacing="0" cellpadding="0" width="100%" border="0">
                  <tbody>
                      <tr>
                          <td class="pageHeading"></td>
                        <td class="pageHeading" align="right"><?php echo zen_draw_separator('pixel_trans.gif', 1, HEADING_IMAGE_HEIGHT); ?></td>
                          <td align="right">
                              <table cellspacing="0" cellpadding="0" width="0%" border="0">
                                  <tbody>
                                      <form method="get" action="orders.php" name="new_special">
                                          <?php if(!empty($_GET['cID'])) {?>
                                              <input type="hidden" name="cID" value=<?php echo $_GET['cID']; ?>>
                                          <?php } ?>
                                        <script language="javascript">
                                            var StartDate = new ctlSpiffyCalendarBox("StartDate", "new_special", "start", "btnDate1","<?php echo (($sInfo->specials_date_available == '0001-01-01') ? '' : zen_date_short($sInfo->specials_date_available)); ?>",scBTNMODE_CUSTOMBLUE);
                                            var EndDate = new ctlSpiffyCalendarBox("EndDate", "new_special", "end", "btnDate2","<?php echo (($sInfo->expires_date == '0001-01-01') ? '' : zen_date_short($sInfo->expires_date)); ?>",scBTNMODE_CUSTOMBLUE);
                                        </script>
                                        <tr>
                                          <script>
                                                document.onreadystatechange = function () {   
                                                     if(document.readyState=="complete") {          
                                                        var obj=document.getElementById("total").innerHTML;
                                                        document.getElementById("allOrderTotal").innerHTML="$"+obj;
                                                      }   
                                                  }
                                                function showTotal(){
                                                    var obj=document.getElementById("total").innerHTML;
                                                    document.getElementById("allOrderTotal").innerHTML="$"+obj;
                                                    }
                                          </script>
                                          <td align="left" colspan=2>All Order Total: <span id="allOrderTotal"></span></td>
                                          <td width="5%" align="right"></td>
                                          <td align="right"><?php echo "Orders start date"; ?>&nbsp;</td>
                                          <td align="right"><script language="javascript">StartDate.writeControl(); StartDate.dateFormat="<?php echo "yyyy/MM/dd"; ?>";</script></td>
                                          <td width="5%" align="right"></td>
                                          <td align="right"><?php echo "Orders end date"; ?>&nbsp;</td>
                                          <td align="right"><script language="javascript">EndDate.writeControl(); EndDate.dateFormat="<?php echo "yyyy/MM/dd"; ?>";</script></td>
                                          <td width="180px" align="center"><?php echo zen_image_submit('button_search.gif','')?></td>
                                        </tr>
                                    </form>
                                </tbody>
                            </table>
                          </td>
                      </tr>
                  </tbody>
              </table>
          </td>
      </tr>
<!-- search -->
<?php } ?>
 
 
<?php
  if (($action == 'edit') && ($order_exists == true)) {
    $order = new order($oID);
    if ($order->info['payment_module_code']) {
      if (file_exists(DIR_FS_CATALOG_MODULES . 'payment/' . $order->info['payment_module_code'] . '.php')) {
        require(DIR_FS_CATALOG_MODULES . 'payment/' . $order->info['payment_module_code'] . '.php');
        require(DIR_FS_CATALOG_LANGUAGES . $_SESSION['language'] . '/modules/payment/' . $order->info['payment_module_code'] . '.php');
        $module = new $order->info['payment_module_code'];
//        echo $module->admin_notification($oID);
      }
    }
?>
      <tr>
        <td width="100%"><table border="0" width="100%" cellspacing="0" cellpadding="0">
          <tr>
            <td class="pageHeading"><?php echo HEADING_TITLE; ?></td>
            <td class="pageHeading" align="right"><?php echo zen_draw_separator('pixel_trans.gif', 1, HEADING_IMAGE_HEIGHT); ?></td>
            <td class="pageHeading" align="right"><?php echo '<a href="javascript:history.back()">' . zen_image_button('button_back.gif', IMAGE_BACK) . '</a>'; ?></td>
          </tr>
        </table></td>
      </tr>
      <tr>
        <td><table width="100%" border="0" cellspacing="0" cellpadding="2">
          <tr>
            <td colspan="3"><?php echo zen_draw_separator(); ?></td>
          </tr>
          <tr>
            <td valign="top"><table width="100%" border="0" cellspacing="0" cellpadding="2">
              <tr>
                <td class="main" valign="top"><strong><?php echo ENTRY_CUSTOMER; ?></strong></td>
                <td class="main"><?php echo zen_address_format($order->customer['format_id'], $order->customer, 1, '', '<br />'); ?></td>
              </tr>
              <tr>
                <td colspan="2"><?php echo zen_draw_separator('pixel_trans.gif', '1', '5'); ?></td>
              </tr>
              <tr>
                <td class="main"><strong><?php echo ENTRY_TELEPHONE_NUMBER; ?></strong></td>
                <td class="main"><?php echo $order->customer['telephone']; ?></td>
              </tr>
              <tr>
                <td class="main"><strong><?php echo ENTRY_EMAIL_ADDRESS; ?></strong></td>
                <td class="main"><?php echo '<a href="mailto:' . $order->customer['email_address'] . '">' . $order->customer['email_address'] . '</a>'; ?></td>
              </tr>
              <tr>
                <td class="main"><strong><?php echo TEXT_INFO_IP_ADDRESS; ?></strong></td>
                <td class="main"><?php echo $order->info['ip_address']; ?></td>
              </tr>
            </table></td>
            <td valign="top"><table width="100%" border="0" cellspacing="0" cellpadding="2">
              <tr>
                <td class="main" valign="top"><strong><?php echo ENTRY_SHIPPING_ADDRESS; ?></strong></td>
                <td class="main"><?php echo zen_address_format($order->delivery['format_id'], $order->delivery, 1, '', '<br />'); ?></td>
              </tr>
            </table></td>
            <td valign="top"><table width="100%" border="0" cellspacing="0" cellpadding="2">
              <tr>
                <td class="main" valign="top"><strong><?php echo ENTRY_BILLING_ADDRESS; ?></strong></td>
                <td class="main"><?php echo zen_address_format($order->billing['format_id'], $order->billing, 1, '', '<br />'); ?></td>
              </tr>
            </table></td>
          </tr>
        </table></td>
      </tr>
      <tr>
        <td><?php echo zen_draw_separator('pixel_trans.gif', '1', '10'); ?></td>
      </tr>
      <tr>
        <td class="main"><strong><?php echo ENTRY_ORDER_ID . $order->info['num']; ?></strong></td>
      </tr>
      <tr>
     <td><table border="0" cellspacing="0" cellpadding="2">
        <tr>
           <td class="main"><strong><?php echo ENTRY_DATE_PURCHASED; ?></strong></td>
           <td class="main"><?php echo zen_date_long($order->info['date_purchased']); ?></td>
        </tr>
        <tr>
           <td class="main"><strong><?php echo ENTRY_PAYMENT_METHOD; ?></strong></td>
           <td class="main"><?php echo $order->info['payment_method']; ?></td>
        </tr>
<?php
    if (zen_not_null($order->info['cc_type']) || zen_not_null($order->info['cc_owner']) || zen_not_null($order->info['cc_number'])) {
?>
          <tr>
            <td colspan="2"><?php echo zen_draw_separator('pixel_trans.gif', '1', '10'); ?></td>
          </tr>
          <tr>
            <td class="main"><?php echo ENTRY_CREDIT_CARD_TYPE; ?></td>
            <td class="main"><?php echo $order->info['cc_type']; ?></td>
          </tr>
          <tr>
            <td class="main"><?php echo ENTRY_CREDIT_CARD_OWNER; ?></td>
            <td class="main"><?php echo $order->info['cc_owner']; ?></td>
          </tr>
          <tr>
            <td class="main"><?php echo ENTRY_CREDIT_CARD_NUMBER; ?></td>
            <td class="main"><?php echo $order->info['cc_number'] . (zen_not_null($order->info['cc_number']) && !strstr($order->info['cc_number'],'X') && !strstr($order->info['cc_number'],'********') ? '&nbsp;&nbsp;<a href="' . zen_href_link(FILENAME_ORDERS, '&action=mask_cc&oID=' . $oID, 'NONSSL') . '" class="noprint">' . TEXT_MASK_CC_NUMBER . '</a>' : ''); ?><td>
          </tr>
<?php if (zen_not_null($order->info['cc_cvv'])) { ?>
          <tr>
            <td class="main"><?php echo ENTRY_CREDIT_CARD_CVV; ?></td>
            <td class="main"><?php echo $order->info['cc_cvv'] . (zen_not_null($order->info['cc_cvv']) && !strstr($order->info['cc_cvv'],TEXT_DELETE_CVV_REPLACEMENT) ? '&nbsp;&nbsp;<a href="' . zen_href_link(FILENAME_ORDERS, '&action=delete_cvv&oID=' . $oID, 'NONSSL') . '" class="noprint">' . TEXT_DELETE_CVV_FROM_DATABASE . '</a>' : ''); ?><td>
          </tr>
<?php } ?>
          <tr>
            <td class="main"><?php echo ENTRY_CREDIT_CARD_EXPIRES; ?></td>
            <td class="main"><?php echo $order->info['cc_expires']; ?></td>
          </tr>
<?php
    }
?>
        </table></td>
      </tr>
<?php
      if (method_exists($module, 'admin_notification')) {
?>
      <tr>
        <td><?php echo zen_draw_separator('pixel_trans.gif', '1', '10'); ?></td>
      </tr>
      <tr>
        <?php echo $module->admin_notification($oID); ?>
      </tr>
      <tr>
        <td><?php echo zen_draw_separator('pixel_trans.gif', '1', '10'); ?></td>
      </tr>
<?php
}
?>
 
<?php 
    //从这里开始,设定为付款订单才能修改价格,5为为付款选项的ID
    if($order->info['orders_status'] == 5){
?>
      <tr><form action="" method="post"><td align="right"><input type="hidden" name="currencies_key" value="<?php echo $order->info['currency']; ?>"><input type="hidden" name="currencies_value" value="<?php echo $order->info['currency_value']; ?>"><input type="button" value="编辑" id="orders_edit"><input style="display: none" type="submit" value="提交" id="orders_submit"><input style="display: none" type="button" value="取消" id="orders_reset"></td></tr>
      <tr id="products_list_changes" style="display: none">
        <td><table border="0" width="100%" cellspacing="0" cellpadding="2">
          <tr class="dataTableHeadingRow">
            <td class="dataTableHeadingContent"><?php echo Image; ?></td>
            <td class="dataTableHeadingContent" colspan="2"><?php echo TABLE_HEADING_PRODUCTS; ?></td>
            <td class="dataTableHeadingContent"><?php echo TABLE_HEADING_PRODUCTS_MODEL; ?></td>
            <td class="dataTableHeadingContent" align="right"><?php echo TABLE_HEADING_TAX; ?></td>
            <td class="dataTableHeadingContent" align="right"><?php echo TABLE_HEADING_PRICE_EXCLUDING_TAX; ?></td>
            <td class="dataTableHeadingContent" align="right"><?php echo TABLE_HEADING_PRICE_INCLUDING_TAX; ?></td>
            <td class="dataTableHeadingContent" align="right"><?php echo TABLE_HEADING_TOTAL_EXCLUDING_TAX; ?></td>
            <td class="dataTableHeadingContent" align="right"><?php echo TABLE_HEADING_TOTAL_INCLUDING_TAX; ?></td>
          </tr>        
 
<?php
 
    for ($i=0, $n=sizeof($order->products); $i<$n; $i++) {    
      $price_input='<input onblur="price_ex_onlive('.$order->products[$i]['id'].','.preg_replace( '/[^\d\.]/', '',$currencies->format($order->products[$i]['final_price'], true, $order->info['currency'], $order->info['currency_value'])).')" onKeyUp="change_price_ex('.$order->products[$i]['id'].','.preg_replace( '/[^\d\.]/', '',$currencies->format($order->products[$i]['final_price'], true, $order->info['currency'], $order->info['currency_value'])).')" size="6" type="text" value="'; 
      $qty_input = '<input onblur="qty_onlive('.$order->products[$i]['id'].','.$order->products[$i]['qty'].')" onKeyUp="change_qty('.$order->products[$i]['id'].')" size="6" type="text" value="';
      $total_input='<input readonly size="6" type="text" value="'; 
      echo '          <tr class="dataTableRow">' . "\n" .
           '            <td><img src="../images/'.$order->products[$i]['image'].'" heiht="80" width="80"/></td>'.
           '            <td class="dataTableContent" valign="top" align="right" style="color:c00">' . $qty_input . $order->products[$i]['qty'] . '" name="qty_'.$order->products[$i]['id'].'">&nbsp;x</td>' . "\n" .
           '            <td class="dataTableContent" valign="top"><a href="'.HTTP_SERVER.DIR_WS_CATALOG.'index.php?main_page=product_info&products_id='.$order->products[$i]['id'].'" target=_blank>'. $order->products[$i]['name'];
 
      if (isset($order->products[$i]['attributes']) && (sizeof($order->products[$i]['attributes']) > 0)) {
        for ($j = 0, $k = sizeof($order->products[$i]['attributes']); $j < $k; $j++) {
          echo '<br /><nobr><small>&nbsp;<i> - ' . $order->products[$i]['attributes'][$j]['option'] . ': ' . nl2br(zen_output_string_protected($order->products[$i]['attributes'][$j]['value']));
          if ($order->products[$i]['attributes'][$j]['price'] != '0') echo ' (' . $order->products[$i]['attributes'][$j]['prefix'] . $currencies->format($order->products[$i]['attributes'][$j]['price'] * $order->products[$i]['qty'], true, $order->info['currency'], $order->info['currency_value']) . ')';
          if ($order->products[$i]['attributes'][$j]['product_attribute_is_free'] == '1' and $order->products[$i]['product_is_free'] == '1') echo TEXT_INFO_ATTRIBUTE_FREE;
          echo '</i></small></nobr>';
        }
      }
 
      echo '            </a></td>' . "\n" .
           '            <td class="dataTableContent" valign="top">' . $order->products[$i]['model'] . '</td>' . "\n" .
           '            <td class="dataTableContent" align="right" valign="top">' . zen_display_tax_value($order->products[$i]['tax']) . '%</td>' . "\n" .
           '            <td class="dataTableContent" align="right" valign="top"><strong>' .$price_input.
                          preg_replace( '/[^\d\.]/', '',$currencies->format($order->products[$i]['final_price'], true, $order->info['currency'], $order->info['currency_value'])).
                          '" name="price_ex_'.$order->products[$i]['id'].'">'.
                          ($order->products[$i]['onetime_charges'] != 0 ? '<br />' . $currencies->format($order->products[$i]['onetime_charges'], true, $order->info['currency'], $order->info['currency_value']) : '') .
                        '</strong></td>' . "\n" .
           '            <td class="dataTableContent" align="right" valign="top"><strong><strong>' . $total_input.
                        preg_replace( '/[^\d\.]/', '',$currencies->format(zen_add_tax($order->products[$i]['final_price'], $order->products[$i]['tax']), true, $order->info['currency'], $order->info['currency_value'])).
                          '" name="price_inc_'.$order->products[$i]['id'].'">'.
                          ($order->products[$i]['onetime_charges'] != 0 ? '<br />' . $currencies->format(zen_add_tax($order->products[$i]['onetime_charges'], $order->products[$i]['tax']), true, $order->info['currency'], $order->info['currency_value']) : '') .
                        '</strong></td>' . "\n" .
           '            <td class="dataTableContent" align="right" valign="top"><strong>' . $total_input.
                          preg_replace( '/[^\d\.]/', '',$currencies->format($order->products[$i]['final_price'] * $order->products[$i]['qty'], true, $order->info['currency'], $order->info['currency_value'])) .
                          '" name="total_ex_'.$order->products[$i]['id'].'">'.
                          ($order->products[$i]['onetime_charges'] != 0 ? '<br />' . $currencies->format($order->products[$i]['onetime_charges'], true, $order->info['currency'], $order->info['currency_value']) : '') .
                        '</strong></td>' . "\n" .
           '            <td class="dataTableContent" align="right" valign="top"><strong>' .$total_input.
                          preg_replace( '/[^\d\.]/', '',$currencies->format(zen_add_tax($order->products[$i]['final_price'], $order->products[$i]['tax']) * $order->products[$i]['qty'], true, $order->info['currency'], $order->info['currency_value'])) .
                          '" name="total_inc_'.$order->products[$i]['id'].'">'.
                          ($order->products[$i]['onetime_charges'] != 0 ? '<br />' . $currencies->format(zen_add_tax($order->products[$i]['onetime_charges'], $order->products[$i]['tax']), true, $order->info['currency'], $order->info['currency_value']) : '') .
                        '</strong></td>' . "\n";
      echo '          </tr>' . "\n";
      echo '          <input type="hidden" name="reference_oid[]" value="'.$order->products[$i]['id'].'">';
    }
    
    echo '<div style="display:none" id="price_total">';
    for ($i=0, $n=sizeof($order->products); $i<$n; $i++){
        echo '<p id="total_ex_hidden_'.$order->products[$i]['id'].'" >'.preg_replace( '/[^\d\.]/', '',$currencies->format($order->products[$i]['final_price'], true, $order->info['currency'], $order->info['currency_value'])) * $order->products[$i]['qty'].'</p>';
    }
    echo '<div>';
?>
          <tr>
            <td align="right" colspan="9"><table border="0" cellspacing="0" cellpadding="2">
<?php
    for ($i = 0, $n = sizeof($order->totals); $i < $n; $i++) {
      echo '              <tr>' . "\n" .
           '                <td align="right" class="'. str_replace('_', '-', $order->totals[$i]['class']) . '-Text">' . $order->totals[$i]['title'] . '</td>' . "\n" ;
      if($order->totals[$i]['class'] == "ot_shipping"){
          echo '                <td align="right"  class="'. str_replace('_', '-', $order->totals[$i]['class']) . '-Amount"><input onblur="shipping_onlive('.preg_replace("/[^\d\.]/", "", $order->totals[$i]['text']).')" onKeyUp="change_shipping('.preg_replace("/[^\d\.]/", "", $order->totals[$i]['text']).')" size="6" type="text" value="' . preg_replace("/[^\d\.]/", "", $order->totals[$i]['text']) . '" name="'.$order->totals[$i]['class'].'"></td>' . "\n";
      }
      else{
          echo '                <td align="right" class="'. str_replace('_', '-', $order->totals[$i]['class']) . '-Amount"><input readonly size="6" type="text" value="' . preg_replace("/[^\d\.]/", "", $order->totals[$i]['text']) . '" name="'.$order->totals[$i]['class'].'"></td>' . "\n";
      }
      echo '              </tr>' . "\n";
    }
?>
            </table></td>
          </tr>
        </table></td>
      </tr>
      </form>
<?php
}
?>
<?php //修改为付款订单代码从这里结束 ?>
 
      <tr id="products_list_default">
        <td><table border="0" width="100%" cellspacing="0" cellpadding="2">
          <tr class="dataTableHeadingRow">
            <td class="dataTableHeadingContent"><?php echo Image; ?></td>
            <td class="dataTableHeadingContent" colspan="2"><?php echo TABLE_HEADING_PRODUCTS; ?></td>
            <td class="dataTableHeadingContent"><?php echo TABLE_HEADING_PRODUCTS_MODEL; ?></td>
            <td class="dataTableHeadingContent" align="right"><?php echo TABLE_HEADING_TAX; ?></td>
            <td class="dataTableHeadingContent" align="right"><?php echo TABLE_HEADING_PRICE_EXCLUDING_TAX; ?></td>
            <td class="dataTableHeadingContent" align="right"><?php echo TABLE_HEADING_PRICE_INCLUDING_TAX; ?></td>
            <td class="dataTableHeadingContent" align="right"><?php echo TABLE_HEADING_TOTAL_EXCLUDING_TAX; ?></td>
            <td class="dataTableHeadingContent" align="right"><?php echo TABLE_HEADING_TOTAL_INCLUDING_TAX; ?></td>
          </tr>
<?php
    for ($i=0, $n=sizeof($order->products); $i<$n; $i++) {     
      echo '          <tr class="dataTableRow">' . "\n" .
           '            <td><img src="../images/'.$order->products[$i]['image'].'" heiht="80" width="80"/></td>'.
           '            <td class="dataTableContent" valign="top" align="right" style="color:c00">' . $order->products[$i]['qty'] . '&nbsp;x</td>' . "\n" .
           '            <td class="dataTableContent" valign="top"><a href="'.HTTP_SERVER.DIR_WS_CATALOG.'index.php?main_page=product_info&products_id='.$order->products[$i]['id'].'" target=_blank>'. $order->products[$i]['name'];
 
      if (isset($order->products[$i]['attributes']) && (sizeof($order->products[$i]['attributes']) > 0)) {
        for ($j = 0, $k = sizeof($order->products[$i]['attributes']); $j < $k; $j++) {
          echo '<br /><nobr><small>&nbsp;<i> - ' . $order->products[$i]['attributes'][$j]['option'] . ': ' . nl2br(zen_output_string_protected($order->products[$i]['attributes'][$j]['value']));
          if ($order->products[$i]['attributes'][$j]['price'] != '0') echo ' (' . $order->products[$i]['attributes'][$j]['prefix'] . $currencies->format($order->products[$i]['attributes'][$j]['price'] * $order->products[$i]['qty'], true, $order->info['currency'], $order->info['currency_value']) . ')';
          if ($order->products[$i]['attributes'][$j]['product_attribute_is_free'] == '1' and $order->products[$i]['product_is_free'] == '1') echo TEXT_INFO_ATTRIBUTE_FREE;
          echo '</i></small></nobr>';
        }
      }
 
      echo '            </a></td>' . "\n" .
           '            <td class="dataTableContent" valign="top">' . $order->products[$i]['model'] . '</td>' . "\n" .
           '            <td class="dataTableContent" align="right" valign="top">' . zen_display_tax_value($order->products[$i]['tax']) . '%</td>' . "\n" .
           '            <td class="dataTableContent" align="right" valign="top"><strong>' .
                          $currencies->format($order->products[$i]['final_price'], true, $order->info['currency'], $order->info['currency_value']) .
                          ($order->products[$i]['onetime_charges'] != 0 ? '<br />' . $currencies->format($order->products[$i]['onetime_charges'], true, $order->info['currency'], $order->info['currency_value']) : '') .
                        '</strong></td>' . "\n" .
           '            <td class="dataTableContent" align="right" valign="top"><strong>' .
                          $currencies->format(zen_add_tax($order->products[$i]['final_price'], $order->products[$i]['tax']), true, $order->info['currency'], $order->info['currency_value']) .
                          ($order->products[$i]['onetime_charges'] != 0 ? '<br />' . $currencies->format(zen_add_tax($order->products[$i]['onetime_charges'], $order->products[$i]['tax']), true, $order->info['currency'], $order->info['currency_value']) : '') .
                        '</strong></td>' . "\n" .
           '            <td class="dataTableContent" align="right" valign="top"><strong>' .
                          $currencies->format($order->products[$i]['final_price'] * $order->products[$i]['qty'], true, $order->info['currency'], $order->info['currency_value']) .
                          ($order->products[$i]['onetime_charges'] != 0 ? '<br />' . $currencies->format($order->products[$i]['onetime_charges'], true, $order->info['currency'], $order->info['currency_value']) : '') .
                        '</strong></td>' . "\n" .
           '            <td class="dataTableContent" align="right" valign="top"><strong>' .
                          $currencies->format(zen_add_tax($order->products[$i]['final_price'], $order->products[$i]['tax']) * $order->products[$i]['qty'], true, $order->info['currency'], $order->info['currency_value']) .
                          ($order->products[$i]['onetime_charges'] != 0 ? '<br />' . $currencies->format(zen_add_tax($order->products[$i]['onetime_charges'], $order->products[$i]['tax']), true, $order->info['currency'], $order->info['currency_value']) : '') .
                        '</strong></td>' . "\n";
      echo '          </tr>' . "\n";
    }
?>
          <tr>
            <td align="right" colspan="9"><table border="0" cellspacing="0" cellpadding="2">
<?php
    for ($i = 0, $n = sizeof($order->totals); $i < $n; $i++) {
      echo '              <tr>' . "\n" .
           '                <td align="right" class="'. str_replace('_', '-', $order->totals[$i]['class']) . '-Text">' . $order->totals[$i]['title'] . '</td>' . "\n" .
           '                <td align="right" class="'. str_replace('_', '-', $order->totals[$i]['class']) . '-Amount">' . $order->totals[$i]['text'] . '</td>' . "\n" .
           '              </tr>' . "\n";
    }
?>
            </table></td>
          </tr>
        </table></td>
      </tr>
 
<?php
  // show downloads
  require(DIR_WS_MODULES . 'orders_download.php');
?>
 
      <tr>
        <td><?php echo zen_draw_separator('pixel_trans.gif', '1', '10'); ?></td>
      </tr>
      <tr>
        <td class="main"><table border="1" cellspacing="0" cellpadding="5">
          <tr>
            <td class="smallText" align="center"><strong><?php echo TABLE_HEADING_DATE_ADDED; ?></strong></td>
            <td class="smallText" align="center"><strong><?php echo TABLE_HEADING_CUSTOMER_NOTIFIED; ?></strong></td>
            <td class="smallText" align="center"><strong><?php echo TABLE_HEADING_STATUS; ?></strong></td>
            <td class="smallText" align="center"><strong><?php echo TABLE_HEADING_COMMENTS; ?></strong></td>
          </tr>
<?php
    $orders_history = $db->Execute("select orders_status_id, date_added, customer_notified, comments
                                    from " . TABLE_ORDERS_STATUS_HISTORY . "
                                    where orders_id = '" . zen_db_input($oID) . "'
                                    order by date_added");
 
    if ($orders_history->RecordCount() > 0) {
      while (!$orders_history->EOF) {
        echo '          <tr>' . "\n" .
             '            <td class="smallText" align="center">' . zen_datetime_short($orders_history->fields['date_added']) . '</td>' . "\n" .
             '            <td class="smallText" align="center">';
        if ($orders_history->fields['customer_notified'] == '1') {
          echo zen_image(DIR_WS_ICONS . 'tick.gif', TEXT_YES) . "</td>\n";
        } else if ($orders_history->fields['customer_notified'] == '-1') {
          echo zen_image(DIR_WS_ICONS . 'locked.gif', TEXT_HIDDEN) . "</td>\n";
        } else {
          echo zen_image(DIR_WS_ICONS . 'unlocked.gif', TEXT_VISIBLE) . "</td>\n";
        }
        echo '            <td class="smallText">' . $orders_status_array[$orders_history->fields['orders_status_id']] . '</td>' . "\n";
        echo '            <td class="smallText">' . nl2br(zen_db_output($orders_history->fields['comments'])) . '&nbsp;</td>' . "\n" .
             '          </tr>' . "\n";
        $orders_history->MoveNext();
      }
    } else {
        echo '          <tr>' . "\n" .
             '            <td class="smallText" colspan="5">' . TEXT_NO_ORDER_HISTORY . '</td>' . "\n" .
             '          </tr>' . "\n";
    }
?>
        </table></td>
      </tr>
      <tr>
        <td class="main noprint"><br /><strong><?php echo TABLE_HEADING_COMMENTS; ?></strong></td>
      </tr>
      <tr>
        <td class="noprint"><?php echo zen_draw_separator('pixel_trans.gif', '1', '5'); ?></td>
      </tr>
      <tr><?php echo zen_draw_form('status', FILENAME_ORDERS, zen_get_all_get_params(array('action')) . 'action=update_order', 'post', '', true); ?>
        <td class="main noprint"><?php echo zen_draw_textarea_field('comments', 'soft', '60', '5'); ?></td>
      </tr>
      <tr>
        <td><?php echo zen_draw_separator('pixel_trans.gif', '1', '10'); ?></td>
      </tr>
      <tr>
        <td><table border="0" cellspacing="0" cellpadding="2" class="noprint">
          <tr>
            <td><table border="0" cellspacing="0" cellpadding="2">
              <tr>
                <td class="main"><strong><?php echo "Tracking Number:"; ?></strong> <?php echo zen_draw_input_field('tracking_number', $order->info['tracking_number']); ?></td>
              </tr> 
              <tr>
                <td class="main"><strong><?php echo ENTRY_STATUS; ?></strong> <?php echo zen_draw_pull_down_menu('status', $orders_statuses, $order->info['orders_status']); ?></td>
              </tr>
              <tr>
                <td class="main"><strong><?php echo ENTRY_NOTIFY_CUSTOMER; ?></strong> [<?php echo zen_draw_radio_field('notify', '1', true) . '-' . TEXT_EMAIL . ' ' . zen_draw_radio_field('notify', '0', FALSE) . '-' . TEXT_NOEMAIL . ' ' . zen_draw_radio_field('notify', '-1', FALSE) . '-' . TEXT_HIDE; ?>]&nbsp;&nbsp;&nbsp;</td>
                <td class="main"><strong><?php echo ENTRY_NOTIFY_COMMENTS; ?></strong> <?php echo zen_draw_checkbox_field('notify_comments', '', true); ?></td>
              </tr>
              <tr><td><br /></td></tr>
            </table></td>
            <td valign="top"><?php echo zen_image_submit('button_update.gif', IMAGE_UPDATE); ?></td>
          </tr>
        </table></td>
      </form></tr>
      <tr>
        <td colspan="2" align="right" class="noprint"><?php echo '<a href="' . zen_href_link(FILENAME_ORDERS_INVOICE, 'oID=' . $_GET['oID']) . '" TARGET="_blank">' . zen_image_button('button_invoice.gif', IMAGE_ORDERS_INVOICE) . '</a> <a href="' . zen_href_link(FILENAME_ORDERS_PACKINGSLIP, 'oID=' . $_GET['oID']) . '" TARGET="_blank">' . zen_image_button('button_packingslip.gif', IMAGE_ORDERS_PACKINGSLIP) . '</a> <a href="' . zen_href_link(FILENAME_ORDERS, zen_get_all_get_params(array('action'))) . '">' . zen_image_button('button_orders.gif', IMAGE_ORDERS) . '</a>'; ?></td>
      </tr>
<?php
// check if order has open gv
        $gv_check = $db->Execute("select order_id, unique_id
                                  from " . TABLE_COUPON_GV_QUEUE ."
                                  where order_id = '" . $_GET['oID'] . "' and release_flag='N' limit 1");
        if ($gv_check->RecordCount() > 0) {
          $goto_gv = '<a href="' . zen_href_link(FILENAME_GV_QUEUE, 'order=' . $_GET['oID']) . '">' . zen_image_button('button_gift_queue.gif',IMAGE_GIFT_QUEUE) . '</a>';
          echo '      <tr><td align="right"><table width="225"><tr>';
          echo '        <td align="center">';
          echo $goto_gv . '&nbsp;&nbsp;';
          echo '        </td>';
          echo '      </tr></table></td></tr>';
        }
?>
<?php
  } else {
?>
      <tr>
        <td width="100%"><table border="0" width="100%" cellspacing="0" cellpadding="0">
          <tr>
            <td class="pageHeading"><?php echo HEADING_TITLE; ?></td>
            <td class="pageHeading" align="right"><?php echo zen_draw_separator('pixel_trans.gif', 1, HEADING_IMAGE_HEIGHT); ?></td>
            <td align="right"><table border="0" width="100%" cellspacing="0" cellpadding="0">
              <tr><?php echo zen_draw_form('orders_num', FILENAME_ORDERS, '', 'get', '', true); ?>
                <td class="smallText" align="right"><?php echo 'order_num' . ' ' . zen_draw_input_field('orders_num', '', 'size="12"') . zen_hide_session_id(); ?></td>
              </form></tr>
              <tr><?php echo zen_draw_form('status', FILENAME_ORDERS, '', 'get', '', true); ?>
                <td class="smallText" align="right">
                  <?php
                    echo HEADING_TITLE_STATUS . ' ' . zen_draw_pull_down_menu('status', array_merge(array(array('id' => '', 'text' => TEXT_ALL_ORDERS)), $orders_statuses), $_GET['status'], 'onChange="this.form.submit();"');
                    echo zen_hide_session_id();
                  ?>
                </td>
              </form></tr>
            </table></td>
          </tr>
        </table></td>
      </tr>
      <tr>
        <td><table border="0" width="100%" cellspacing="0" cellpadding="0">
          <tr>
             <td class="smallText">
                <?php echo TEXT_LEGEND . ' ' . zen_image(DIR_WS_IMAGES . 'icon_status_red.gif', TEXT_BILLING_SHIPPING_MISMATCH, 10, 10) . ' ' . TEXT_BILLING_SHIPPING_MISMATCH; ?>
                <?php echo zen_image(DIR_WS_IMAGES . 'icon_green_on.gif', IMAGE_ICON_STATUS_ON)."PCB Order"; ?>
                <?php echo zen_image(DIR_WS_IMAGES . 'icon_red_on.gif', IMAGE_ICON_STATUS_ON)."PRE Order"; ?>
                <?php echo zen_image(DIR_WS_IMAGES . 'icon_yellow_on.gif', IMAGE_ICON_STATUS_ON)."Customer Comments"; ?>
              </td>
          <tr>
            <td valign="top"><table border="0" width="100%" cellspacing="0" cellpadding="2">
              <tr class="dataTableHeadingRow">
<?php
// Sort Listing
          switch ($_GET['list_order']) {
              case "id-asc":
              $disp_order = "c.customers_id";
              break;
              case "firstname":
              $disp_order = "c.customers_firstname";
              break;
              case "firstname-desc":
              $disp_order = "c.customers_firstname DESC";
              break;
              case "lastname":
              $disp_order = "c.customers_lastname, c.customers_firstname";
              break;
              case "lastname-desc":
              $disp_order = "c.customers_lastname DESC, c.customers_firstname";
              break;
              case "company":
              $disp_order = "a.entry_company";
              break;
              case "company-desc":
              $disp_order = "a.entry_company DESC";
              break;
              default:
              $disp_order = "c.customers_id DESC";
          }
?>
                <td class="dataTableHeadingContent" align="center"><?php echo TABLE_HEADING_ORDERS_ID; ?></td>
                <td class="dataTableHeadingContent" align="left" width="50"><?php echo TABLE_HEADING_PAYMENT_METHOD; ?></td>
                <td class="dataTableHeadingContent"><?php echo TABLE_HEADING_CUSTOMERS; ?></td>
                <td class="dataTableHeadingContent" align="right"><?php echo TABLE_HEADING_ORDER_TOTAL; ?></td>
                <td class="dataTableHeadingContent" align="center"><?php echo TABLE_HEADING_DATE_PURCHASED; ?></td>
                <td class="dataTableHeadingContent" align="right"><?php echo TABLE_HEADING_STATUS; ?></td>
                <td class="dataTableHeadingContent" align="center"><?php echo TABLE_HEADING_CUSTOMER_COMMENTS; ?></td>
                <td class="dataTableHeadingContent" align="center"><input type="checkbox" id="select_all" onclick="selectAll()"></td>
                <td class="dataTableHeadingContent" align="right"><?php echo TABLE_HEADING_ACTION; ?>&nbsp;</td>
              </tr>
 
<?php
// Only one or the other search
// create search_orders_products filter
  $search = '';
  $new_table = '';
  $new_fields = '';
  if (isset($_GET['search_orders_products']) && zen_not_null($_GET['search_orders_products'])) {
    $new_fields = '';
    $search_distinct = ' distinct ';
    $new_table = " left join " . TABLE_ORDERS_PRODUCTS . " op on (op.orders_id = o.orders_id) ";
    $keywords = zen_db_input(zen_db_prepare_input($_GET['search_orders_products']));
    $search = " and (op.products_model like '%" . $keywords . "%' or op.products_name like '%" . $keywords . "%')";
    if (substr(strtoupper($_GET['search_orders_products']), 0, 3) == 'ID:') {
      $keywords = TRIM(substr($_GET['search_orders_products'], 3));
      $search = " and op.products_id ='" . (int)$keywords . "'";
    }
  } else {
?>
<?php
// create search filter
  $search = '';
  if (isset($_GET['search']) && zen_not_null($_GET['search'])) {
    $search_distinct = ' ';
    $keywords = zen_db_input(zen_db_prepare_input($_GET['search']));
    $search = " and (o.customers_city like '%" . $keywords . "%' or o.orders_num like '%" . $keywords ."%' or o.customers_postcode like '%" . $keywords . "%' or o.date_purchased like '%" . $keywords . "%' or o.billing_name like '%" . $keywords . "%' or o.billing_company like '%" . $keywords . "%' or o.billing_street_address like '%" . $keywords . "%' or o.delivery_city like '%" . $keywords . "%' or o.delivery_postcode like '%" . $keywords . "%' or o.delivery_name like '%" . $keywords . "%' or o.delivery_company like '%" . $keywords . "%' or o.delivery_street_address like '%" . $keywords . "%' or o.billing_city like '%" . $keywords . "%' or o.billing_postcode like '%" . $keywords . "%' or o.customers_email_address like '%" . $keywords . "%' or o.customers_name like '%" . $keywords . "%' or o.customers_company like '%" . $keywords . "%' or o.customers_street_address  like '%" . $keywords . "%' or o.customers_telephone like '%" . $keywords . "%' or o.ip_address  like '%" . $keywords . "%')";
    $new_table = '';
//    $new_fields = ", o.customers_company, o.customers_email_address, o.customers_street_address, o.delivery_company, o.delivery_name, o.delivery_street_address, o.billing_company, o.billing_name, o.billing_street_address, o.payment_module_code, o.shipping_module_code, o.ip_address ";
  }
  if(isset($_GET['orders_num']) && zen_not_null($_GET['orders_num'])){
    $search_distinct = ' ';
    $keywords = zen_db_input(zen_db_prepare_input($_GET['orders_num']));
    $search = " and (o.orders_num like '%" .$keywords ."%') ";
    $new_table = '';
  }
} // eof: search orders or orders_products
    $new_fields = ", o.customers_company, o.customers_email_address, o.customers_street_address, o.delivery_company, o.delivery_name, o.delivery_street_address, o.billing_company, o.billing_name, o.billing_street_address, o.payment_module_code, o.shipping_module_code, o.ip_address ";
?>
<?php
      if (isset($_GET['cID'])) {
            $cID = zen_db_prepare_input($_GET['cID']);
          //add code
          if(isset($_GET['start']) || isset($_GET['end'])){
              if(!empty($_GET['start']) && empty($_GET['end'])){
                  $start_time = strtr($_GET['start'], "/", "-");
                  $order_time = " and o.date_purchased >= '".$start_time."' ";
              }
              if(empty($_GET['start']) && !empty($_GET['end'])){
                  $end_time = strtr($_GET['end'], "/", "-");
                  $order_time = " and o.date_purchased <= '".$end_time."' ";
              }
              if(!empty($_GET['start']) && !empty($_GET['end'])){
                  $start_time = strtr($_GET['start'], "/", "-");
                  $end_time = strtr($_GET['end'], "/", "-")." 23:59:59";
                  $order_time = " and o.date_purchased >= ' " .$start_time. "' and o.date_purchased <= '".$end_time."' ";
              }
          
              $orders_query_raw =   "select o.orders_id, orders_num, o.customers_id, o.customers_name, o.payment_method, o.shipping_method, o.date_purchased, o.last_modified, o.currency, o.currency_value, o.date_purchased, o.order_total as total, s.orders_status_name, ot.text as order_total" .
                                        $new_fields . "
                                        from (" . TABLE_ORDERS_STATUS . " s, " .
                                        TABLE_ORDERS . " o " .
                                        $new_table . ")
                                        left join " . TABLE_ORDERS_TOTAL . " ot on (o.orders_id = ot.orders_id and ot.class = 'ot_total') " . "
                                        where o.customers_id = '" . (int)$cID . "' and o.orders_status = s.orders_status_id ".$order_time." and s.language_id = '" . (int)$_SESSION['languages_id'] . "' order by orders_id DESC";
          }else{      
              $orders_query_raw =   "select o.orders_id, orders_num, o.customers_id, o.customers_name, o.payment_method, o.shipping_method, o.date_purchased, o.last_modified, o.currency, o.currency_value, o.order_total as total, s.orders_status_name, ot.text as order_total" .
                                    $new_fields . "
                                    from (" . TABLE_ORDERS_STATUS . " s, " .
                                    TABLE_ORDERS . " o " .
                                    $new_table . ")
                                    left join " . TABLE_ORDERS_TOTAL . " ot on (o.orders_id = ot.orders_id and ot.class = 'ot_total') " . "
                                    where o.customers_id = '" . (int)$cID . "' and o.orders_status = s.orders_status_id and s.language_id = '" . (int)$_SESSION['languages_id'] . "' order by orders_id DESC";
          }
 
      } 
      elseif ($_GET['status'] != '') {
      $status = zen_db_prepare_input($_GET['status']);
      $orders_query_raw = "select o.orders_id, orders_num, o.customers_id, o.customers_name, o.payment_method, o.shipping_method, o.date_purchased, o.last_modified, o.currency, o.currency_value, o.order_total as total, s.orders_status_name, ot.text as order_total" .
                          $new_fields . "
                          from (" . TABLE_ORDERS_STATUS . " s, " .
                          TABLE_ORDERS . " o " .
                          $new_table . ")
                          left join " . TABLE_ORDERS_TOTAL . " ot on (o.orders_id = ot.orders_id and ot.class = 'ot_total') " . "
                          where o.orders_status = s.orders_status_id and s.language_id = '" . (int)$_SESSION['languages_id'] . "' and s.orders_status_id = '" . (int)$status . "'  " .
                          $search . " order by o.orders_id DESC";
 
    }
    else {
      //add code
      if(isset($_GET['start']) || isset($_GET['end'])){
          if(!empty($_GET['start']) && empty($_GET['end'])){
              $start_time = strtr($_GET['start'], "/", "-");
              $order_time = " and orders_status <> 11 and o.date_purchased >= '".$start_time."' ";
          }
          if(empty($_GET['start']) && !empty($_GET['end'])){
              $end_time = strtr($_GET['end'], "/", "-");
              $order_time = " and orders_status <> 11 and o.date_purchased <= '".$end_time."' ";
          }
          if(!empty($_GET['start']) && !empty($_GET['end'])){
              $start_time = strtr($_GET['start'], "/", "-");
              $end_time = strtr($_GET['end'], "/", "-")." 23:59:59";
              $order_time = " and orders_status <> 11 and o.date_purchased >= ' " .$start_time. "' and o.date_purchased <= '".$end_time."' ";
          }
          $orders_query_raw = "select " . $search_distinct . " o.orders_id, orders_num, o.customers_id, o.customers_name, o.payment_method, o.shipping_method, o.date_purchased, o.last_modified, o.currency, o.currency_value, o.date_purchased, o.date_purchased, o.order_total as total, s.orders_status_name, ot.text as order_total" .
                          $new_fields . "
                          from (" . TABLE_ORDERS_STATUS . " s, " .
                          TABLE_ORDERS . " o " .
                          $new_table . ")
                          left join " . TABLE_ORDERS_TOTAL . " ot on (o.orders_id = ot.orders_id and ot.class = 'ot_total') " . "
                          where (o.orders_status = s.orders_status_id and s.language_id = '" . (int)$_SESSION['languages_id'] . "')  " .
                          $search . $order_time. " order by o.orders_id DESC";
      }else{   
          $orders_query_raw = "select " . $search_distinct . " o.orders_id, orders_num, o.customers_id, o.customers_name, o.payment_method, o.shipping_method, o.date_purchased, o.last_modified, o.currency, o.currency_value, o.date_purchased, o.order_total as total, s.orders_status_name, ot.text as order_total" .
                          $new_fields . "
                          from (" . TABLE_ORDERS_STATUS . " s, " .
                          TABLE_ORDERS . " o " .
                          $new_table . ")
                          left join " . TABLE_ORDERS_TOTAL . " ot on (o.orders_id = ot.orders_id and ot.class = 'ot_total') " . "
                          where (o.orders_status = s.orders_status_id and s.language_id = '" . (int)$_SESSION['languages_id'] . "')  " .
                          $search . " order by o.orders_id DESC";
      }
    }
 
// Split Page
// reset page when page is unknown
if (($_GET['page'] == '' or $_GET['page'] <= 1) and $_GET['oID'] != '') {
  $check_page = $db->Execute($orders_query_raw);
  $check_count=1;
  if ($check_page->RecordCount() > MAX_DISPLAY_SEARCH_RESULTS_ORDERS) {
    while (!$check_page->EOF) {
      if ($check_page->fields['orders_id'] == $_GET['oID']) {
        break;
      }
      $check_count++;
      $check_page->MoveNext();
    }
    $_GET['page'] = round((($check_count/MAX_DISPLAY_SEARCH_RESULTS_ORDERS)+(fmod_round($check_count,MAX_DISPLAY_SEARCH_RESULTS_ORDERS) !=0 ? .5 : 0)),0);
  } else {
    $_GET['page'] = 1;
  }
}
 
    //all order total
    $orders = $db->Execute($orders_query_raw);
    $total="";
    while (!$orders->EOF) {
        $total+=$orders->fields['total'];
        $orders->MoveNext();
    }
    if(!empty($total)){
        echo '<div id="total" style="display:none">'.$total.'</div>';
    }
 
//    $orders_query_numrows = '';
    $orders_split = new splitPageResults($_GET['page'], MAX_DISPLAY_SEARCH_RESULTS_ORDERS, $orders_query_raw, $orders_query_numrows);
    $orders = $db->Execute($orders_query_raw);
    echo zen_draw_form('status', FILENAME_ORDERS, '', 'post', '', true);
    while (!$orders->EOF) {
    if ((!isset($_GET['oID']) || (isset($_GET['oID']) && ($_GET['oID'] == $orders->fields['orders_id']))) && !isset($oInfo)) {
        $oInfo = new objectInfo($orders->fields);
      }
 
      if (isset($oInfo) && is_object($oInfo) && ($orders->fields['orders_id'] == $oInfo->orders_id)) {
        echo '              <tr id="defaultSelected" class="dataTableRowSelected" onmouseover="rowOverEffect(this)" onmouseout="rowOutEffect(this)" onclick="document.location.href=\'' . zen_href_link(FILENAME_ORDERS, zen_get_all_get_params(array('oID', 'action')) . 'oID=' . $oInfo->orders_id . '&action=edit', 'NONSSL') . '\'">' . "\n";
      } else {
        //echo '              <tr class="dataTableRow" onmouseover="rowOverEffect(this)" onmouseout="rowOutEffect(this)" onclick="document.location.href=\'' . zen_href_link(FILENAME_ORDERS, zen_get_all_get_params(array('oID')) . 'oID=' . $orders->fields['orders_id'], 'NONSSL') . '\'">' . "\n";
        echo '              <tr class="dataTableRow" onmouseover="rowOverEffect(this)" onmouseout="rowOutEffect(this)">' . "\n";
      }
 
      $show_difference = '';
      if (($orders->fields['delivery_name'] != $orders->fields['billing_name'] and $orders->fields['delivery_name'] != '')) {
        $show_difference = zen_image(DIR_WS_IMAGES . 'icon_status_red.gif', TEXT_BILLING_SHIPPING_MISMATCH, 10, 10) . '&nbsp;';
      }
      if (($orders->fields['delivery_street_address'] != $orders->fields['billing_street_address'] and $orders->fields['delivery_street_address'] != '')) {
        $show_difference = zen_image(DIR_WS_IMAGES . 'icon_status_red.gif', TEXT_BILLING_SHIPPING_MISMATCH, 10, 10) . '&nbsp;';
      }
      $show_payment_type = $orders->fields['payment_module_code'] . '<br />' . $orders->fields['shipping_module_code'];
?>
<?php
                if(!empty($_GET['cID']) || !empty($_GET['search']) || !empty($_GET['orders_num']) || !empty($_GET['search_orders_products'])){
                    
                    $attributes = $db->Execute("select products_options_id
                                                from " . TABLE_ORDERS_PRODUCTS_ATTRIBUTES . "
                                                where orders_id = '" . $orders->fields['orders_id'] . "' and products_options_id ='5'");
                    
                    $order_products = $db->Execute("select products_total_quantity
                                                    from ". TABLE_ORDERS_PRODUCTS ."
                                                    where orders_id=" .$orders->fields['orders_id'] . " AND products_total_quantity < 0 ORDER BY products_total_quantity ");
                
                }
                else{
                    $attributes = $db->Execute("select products_options_id
                                                from " . TABLE_ORDERS_PRODUCTS_ATTRIBUTES . "
                                                where orders_id = '" . $orders->fields['orders_id'] . "' and products_options_id ='5'");
                    if(!empty($attributes->fields)){
                        $orders->MoveNext();
                        continue;
                    }
                    
                    $order_products = $db->Execute("select products_total_quantity
                                                    from ". TABLE_ORDERS_PRODUCTS ."
                                                    where orders_id=" .$orders->fields['orders_id'] . " AND products_total_quantity < 0 ORDER BY products_total_quantity ");
                    if($order_products->fields) {
                        $orders->MoveNext();
                        continue;
                    }
                }
                
                $onclick = 'onclick="document.location.href=\'' . zen_href_link(FILENAME_ORDERS, zen_get_all_get_params(array('oID')) . 'oID=' . $orders->fields['orders_id'], 'NONSSL') . '\'"';
                
                if(empty($show_difference)) $p='&nbsp&nbsp&nbsp&nbsp';
                else $p='';
?>
                <td class="dataTableContent" align="left" <?php echo $onclick; ?> ><?php echo $show_difference.$p.$orders->fields['orders_num']; ?></td>
                <td class="dataTableContent" align="left" width="50" <?php echo $onclick; ?> ><?php echo $show_payment_type; ?></td>
                <td class="dataTableContent" <?php echo $onclick; ?> ><?php echo '<a href="' . zen_href_link(FILENAME_CUSTOMERS, 'cID=' . $orders->fields['customers_id'], 'NONSSL') . '">' . zen_image(DIR_WS_ICONS . 'preview.gif', ICON_PREVIEW . ' ' . TABLE_HEADING_CUSTOMERS) . '</a>&nbsp;' . $orders->fields['customers_name'] . ($orders->fields['customers_company'] != '' ? '<br />' . $orders->fields['customers_company'] : ''); ?></td>
                <td class="dataTableContent" align="right" <?php echo $onclick; ?> ><?php echo strip_tags($orders->fields['order_total']); ?></td>
                <td class="dataTableContent" align="center" <?php echo $onclick; ?> ><?php echo zen_datetime_short($orders->fields['date_purchased']); ?></td>
                <td class="dataTableContent" align="right" <?php echo $onclick; ?> ><?php echo $orders->fields['orders_status_name']; ?></td>
                <td class="dataTableContent" align="center" <?php echo $onclick; ?> ><?php echo (zen_get_orders_comments($orders->fields['orders_id']) == '' ? '' : zen_image(DIR_WS_IMAGES . 'icon_yellow_on.gif', TEXT_COMMENTS_YES, 16, 16)); ?><?php echo (!empty($attributes->fields) ? zen_image(DIR_WS_IMAGES . 'icon_green_on.gif', IMAGE_ICON_STATUS_ON):''); ?><?php echo (!empty($order_products->fields) ? zen_image(DIR_WS_IMAGES . 'icon_red_on.gif', ICON_EDIT) : ""); ?></td>
                <td class="dataTableContent" align="center"><input type="checkbox" name="order_id[]" value="<?php echo $orders->fields['orders_id']; ?>"></td>
                <td class="dataTableContent" align="right" <?php echo $onclick; ?> ><?php echo '<a href="' . zen_href_link(FILENAME_ORDERS, zen_get_all_get_params(array('oID', 'action')) . 'oID=' . $orders->fields['orders_id'] . '&action=edit', 'NONSSL') . '">' . zen_image(DIR_WS_IMAGES . 'icon_edit.gif', ICON_EDIT) . '</a>'; ?><?php if (isset($oInfo) && is_object($oInfo) && ($orders->fields['orders_id'] == $oInfo->orders_id)) { echo zen_image(DIR_WS_IMAGES . 'icon_arrow_right.gif', ''); } else { echo '<a href="' . zen_href_link(FILENAME_ORDERS, zen_get_all_get_params(array('oID')) . 'oID=' . $orders->fields['orders_id'], 'NONSSL') . '">' . zen_image(DIR_WS_IMAGES . 'icon_info.gif', IMAGE_ICON_INFO) . '</a>'; } ?></td>
            </tr>
<?php
      $orders->MoveNext();
    }
?>
              <tr>
                <td class="smallText" align="right"  colspan="8"><input type="submit" value="Export Orders"></form></td>
              </tr>
              <tr>
                <td colspan="5"><table border="0" width="100%" cellspacing="0" cellpadding="2">
                  <tr>
                    <td class="smallText" valign="top"><?php echo $orders_split->display_count($orders_query_numrows, MAX_DISPLAY_SEARCH_RESULTS_ORDERS, $_GET['page'], TEXT_DISPLAY_NUMBER_OF_ORDERS); ?></td>
                    <td class="smallText" align="right"><?php echo $orders_split->display_links($orders_query_numrows, MAX_DISPLAY_SEARCH_RESULTS_ORDERS, MAX_DISPLAY_PAGE_LINKS, $_GET['page'], zen_get_all_get_params(array('page', 'oID', 'action'))); ?></td>
                  </tr>
<?php
  if (isset($_GET['search']) && zen_not_null($_GET['search'])) {
?>
                  <tr>
                    <td class="smallText" align="right" colspan="2">
                      <?php
                        echo '<a href="' . zen_href_link(FILENAME_ORDERS, '', 'NONSSL') . '">' . zen_image_button('button_reset.gif', IMAGE_RESET) . '</a>';
                        if (isset($_GET['search']) && zen_not_null($_GET['search'])) {
                          $keywords = zen_db_input(zen_db_prepare_input($_GET['search']));
                          echo '<br/ >' . TEXT_INFO_SEARCH_DETAIL_FILTER . $keywords;
                        }
                      ?>
                    </td>
                  </tr>
<?php
  }
?>
                </table></td>
              </tr>
            </table></td>
<?php
  $heading = array();
  $contents = array();
 
  switch ($action) {
    case 'delete':
      $heading[] = array('text' => '<strong>' . TEXT_INFO_HEADING_DELETE_ORDER . '</strong>');
 
      $contents = array('form' => zen_draw_form('orders', FILENAME_ORDERS, zen_get_all_get_params(array('oID', 'action')) . 'oID=' . $oInfo->orders_id . '&action=deleteconfirm', 'post', '', true));
//      $contents[] = array('text' => TEXT_INFO_DELETE_INTRO . '<br /><br /><strong>' . $cInfo->customers_firstname . ' ' . $cInfo->customers_lastname . '</strong>');
      $contents[] = array('text' => TEXT_INFO_DELETE_INTRO . '<br /><br /><strong>' . ENTRY_ORDER_ID . $oInfo->orders_num . '<br />' . $oInfo->order_total . '<br />' . $oInfo->customers_name . ($oInfo->customers_company != '' ? '<br />' . $oInfo->customers_company : '') . '</strong>');
      $contents[] = array('text' => '<br />' . zen_draw_checkbox_field('restock') . ' ' . TEXT_INFO_RESTOCK_PRODUCT_QUANTITY);
      $contents[] = array('align' => 'center', 'text' => '<br />' . zen_image_submit('button_delete.gif', IMAGE_DELETE) . ' <a href="' . zen_href_link(FILENAME_ORDERS, zen_get_all_get_params(array('oID', 'action')) . 'oID=' . $oInfo->orders_id, 'NONSSL') . '">' . zen_image_button('button_cancel.gif', IMAGE_CANCEL) . '</a>');
      break;
    default:
      if (isset($oInfo) && is_object($oInfo)) {
        $heading[] = array('text' => '<strong>[' . $oInfo->orders_id . ']&nbsp;&nbsp;' . zen_datetime_short($oInfo->date_purchased) . '</strong>');
 
        $contents[] = array('align' => 'center', 'text' => '<a href="' . zen_href_link(FILENAME_ORDERS, zen_get_all_get_params(array('oID', 'action')) . 'oID=' . $oInfo->orders_id . '&action=edit', 'NONSSL') . '">' . zen_image_button('button_edit.gif', IMAGE_EDIT) . '</a> <a href="' . zen_href_link(FILENAME_ORDERS, zen_get_all_get_params(array('oID', 'action')) . 'oID=' . $oInfo->orders_id . '&action=delete', 'NONSSL') . '">' . zen_image_button('button_delete.gif', IMAGE_DELETE) . '</a>');
        $contents[] = array('align' => 'center', 'text' => '<a href="' . zen_href_link(FILENAME_ORDERS_INVOICE, 'oID=' . $oInfo->orders_id) . '" TARGET="_blank">' . zen_image_button('button_invoice.gif', IMAGE_ORDERS_INVOICE) . '</a> <a href="' . zen_href_link(FILENAME_ORDERS_PACKINGSLIP, 'oID=' . $oInfo->orders_id) . '" TARGET="_blank">' . zen_image_button('button_packingslip.gif', IMAGE_ORDERS_PACKINGSLIP) . '</a>');
        $contents[] = array('align' => 'center', 'text' => '<a href="' . zen_href_link(FILENAME_ORDERS, 'cID=' . $oInfo->customers_id) . '" ">' . zen_image_button('button_allroder.gif', "All order") . '</a>');
        $contents[] = array('text' => '<br />' . TEXT_DATE_ORDER_CREATED . ' ' . zen_date_short($oInfo->date_purchased));
        $contents[] = array('text' => '<br />' . $oInfo->customers_email_address);
        $contents[] = array('text' => TEXT_INFO_IP_ADDRESS . ' ' . $oInfo->ip_address);
        if (zen_not_null($oInfo->last_modified)) $contents[] = array('text' => TEXT_DATE_ORDER_LAST_MODIFIED . ' ' . zen_date_short($oInfo->last_modified));
        $contents[] = array('text' => '<br />' . TEXT_INFO_PAYMENT_METHOD . ' '  . $oInfo->payment_method);
        $contents[] = array('text' => '<br />' . ENTRY_SHIPPING . ' '  . $oInfo->shipping_method);
 
// check if order has open gv
        $gv_check = $db->Execute("select order_id, unique_id
                                  from " . TABLE_COUPON_GV_QUEUE ."
                                  where order_id = '" . $oInfo->orders_id . "' and release_flag='N' limit 1");
        if ($gv_check->RecordCount() > 0) {
          $goto_gv = '<a href="' . zen_href_link(FILENAME_GV_QUEUE, 'order=' . $oInfo->orders_id) . '">' . zen_image_button('button_gift_queue.gif',IMAGE_GIFT_QUEUE) . '</a>';
          $contents[] = array('text' => '<br />' . zen_image(DIR_WS_IMAGES . 'pixel_black.gif','','100%','3'));
          $contents[] = array('align' => 'center', 'text' => $goto_gv);
        }
      }
 
// indicate if comments exist
      $orders_history_query = $db->Execute("select orders_status_id, date_added, customer_notified, comments from " . TABLE_ORDERS_STATUS_HISTORY . " where orders_id = '" . $oInfo->orders_id . "' and comments !='" . "'" );
      if ($orders_history_query->RecordCount() > 0) {
        $contents[] = array('align' => 'left', 'text' => '<br />' . TABLE_HEADING_COMMENTS);
      }
 
      $contents[] = array('text' => '<br />' . zen_image(DIR_WS_IMAGES . 'pixel_black.gif','','100%','3'));
      $order = new order($oInfo->orders_id);
      $contents[] = array('text' => 'Products Ordered: ' . sizeof($order->products) );
      for ($i=0; $i<sizeof($order->products); $i++) {
        $contents[] = array('text' => $order->products[$i]['qty'] . '&nbsp;x&nbsp;' . $order->products[$i]['name']);
 
        if (sizeof($order->products[$i]['attributes']) > 0) {
          for ($j=0; $j<sizeof($order->products[$i]['attributes']); $j++) {
            $contents[] = array('text' => '&nbsp;<i> - ' . $order->products[$i]['attributes'][$j]['option'] . ': ' . nl2br(zen_output_string_protected($order->products[$i]['attributes'][$j]['value'])) . '</i></nobr>' );
          }
        }
        if ($i > MAX_DISPLAY_RESULTS_ORDERS_DETAILS_LISTING and MAX_DISPLAY_RESULTS_ORDERS_DETAILS_LISTING != 0) {
          $contents[] = array('align' => 'left', 'text' => TEXT_MORE);
          break;
        }
      }
 
      if (sizeof($order->products) > 0) {
        $contents[] = array('align' => 'center', 'text' => '<a href="' . zen_href_link(FILENAME_ORDERS, zen_get_all_get_params(array('oID', 'action')) . 'oID=' . $oInfo->orders_id . '&action=edit', 'NONSSL') . '">' . zen_image_button('button_edit.gif', IMAGE_EDIT) . '</a>');
      }
      break;
  }
 
  if ( (zen_not_null($heading)) && (zen_not_null($contents)) ) {
    echo '            <td width="25%" valign="top">' . "\n";
 
    $box = new box;
    echo $box->infoBox($heading, $contents);
 
    echo '            </td>' . "\n";
  }
?>
          </tr>
        </table></td>
      </tr>
<?php
  }
?>
    </table></td>
<!-- body_text_eof //-->
  </tr>
</table>
<!-- body_eof //-->
 
<!-- footer //-->
<div class="footer-area">
<?php require(DIR_WS_INCLUDES . 'footer.php'); ?>
</div>
<!-- footer_eof //-->
<br />
</body>
</html>
<?php require(DIR_WS_INCLUDES . 'application_bottom.php'); ?>

10. 修改付款后,给客户发送邮件的问题。注销 includes/modules/checkout_process.php 文件的 $order->send_order_email($insert_id, 2);  这是生成订单的时候发送订单邮件,不是付款成功时发送邮件,所以需要注销掉,当然你也可以自己写邮件,当订单生成后,可以发送提示邮件给客户。付款成功后发送邮件功能调用在 ipn_main_handler.php 文件中。发送邮件函数是在 includes/classes/order.php 文件的 send_order_email($zf_insert_id, $zf_mode) 函数,代码修改如下:

function send_order_email($zf_insert_id, $zf_mode) {
    global $currencies, $order_totals;
    if( !empty($this->totals) ){
        $order_totals = $this->totals;
    }
    if ($this->email_low_stock != '' and SEND_LOWSTOCK_EMAIL=='1') {
      // send an email
      $email_low_stock = SEND_EXTRA_LOW_STOCK_EMAIL_TITLE . "\n\n" . $this->email_low_stock;
      zen_mail('', SEND_EXTRA_LOW_STOCK_EMAILS_TO, EMAIL_TEXT_SUBJECT_LOWSTOCK, $email_low_stock, STORE_OWNER, EMAIL_FROM, array('EMAIL_MESSAGE_HTML' => nl2br($email_low_stock)),'low_stock');
    }
 
    // lets start with the email confirmation
    // make an array to store the html version
    $html_msg=array();
 
    //intro area
    $email_order = EMAIL_TEXT_HEADER . EMAIL_TEXT_FROM . STORE_NAME . "\n\n" .
    $this->customer['firstname'] . ' ' . $this->customer['lastname'] . "\n\n" .
    EMAIL_THANKS_FOR_SHOPPING . "\n" . EMAIL_DETAILS_FOLLOW . "\n" .
    EMAIL_SEPARATOR . "\n" .
    EMAIL_TEXT_ORDER_NUMBER . ' ' . zen_get_order_orders_number($zf_insert_id) . "\n" .
    EMAIL_TEXT_DATE_ORDERED . ' ' . strftime(DATE_FORMAT_LONG) . "\n" .
    EMAIL_TEXT_INVOICE_URL . ' ' . zen_href_link(FILENAME_ACCOUNT_HISTORY_INFO, 'order_id=' . $zf_insert_id, 'SSL', false) . "\n\n";
    $html_msg['EMAIL_TEXT_HEADER']     = EMAIL_TEXT_HEADER;
    $html_msg['EMAIL_TEXT_FROM']       = EMAIL_TEXT_FROM;
    $html_msg['INTRO_STORE_NAME']      = STORE_NAME;
    $html_msg['EMAIL_THANKS_FOR_SHOPPING'] = EMAIL_THANKS_FOR_SHOPPING;
    $html_msg['EMAIL_DETAILS_FOLLOW']  = EMAIL_DETAILS_FOLLOW;
    $html_msg['INTRO_ORDER_NUM_TITLE'] = EMAIL_TEXT_ORDER_NUMBER;
    $html_msg['INTRO_ORDER_NUMBER']    = zen_get_order_orders_number($zf_insert_id);
    $html_msg['INTRO_DATE_TITLE']      = EMAIL_TEXT_DATE_ORDERED;
    $html_msg['INTRO_DATE_ORDERED']    = strftime(DATE_FORMAT_LONG);
    $html_msg['INTRO_URL_TEXT']        = EMAIL_TEXT_INVOICE_URL_CLICK;
    $html_msg['INTRO_URL_VALUE']       = zen_href_link(FILENAME_ACCOUNT_HISTORY_INFO, 'order_id=' . $zf_insert_id, 'SSL', false);
 
    //comments area
    if ($this->info['comments']) {
      $email_order .= zen_db_output($this->info['comments']) . "\n\n";
      $html_msg['ORDER_COMMENTS'] = nl2br(zen_db_output($this->info['comments']));
    } else {
      $html_msg['ORDER_COMMENTS'] = '';
    }
 
    //products area
    $email_order .= EMAIL_TEXT_PRODUCTS . "\n" .
    EMAIL_SEPARATOR . "\n" .
    $this->products_ordered .
    EMAIL_SEPARATOR . "\n";
    $html_msg['PRODUCTS_TITLE'] = EMAIL_TEXT_PRODUCTS;
    $html_msg['PRODUCTS_DETAIL']='<table class="product-details" border="0" width="100%" cellspacing="0" cellpadding="2">' . $this->products_ordered_html . '</table>';
 
    //order totals area
    $html_ot .= '<td class="order-totals-text" align="right" width="100%">' . '&nbsp;' . '</td> ' . "\n" . '<td class="order-totals-num" align="right" nowrap="nowrap">' . '---------' .'</td> </tr>' . "\n" . '<tr>';
    for ($i=0, $n=sizeof($order_totals); $i<$n; $i++) {
      $email_order .= strip_tags($order_totals[$i]['title']) . ' ' . strip_tags($order_totals[$i]['text']) . "\n";
      $html_ot .= '<td class="order-totals-text" align="right" width="100%">' . $order_totals[$i]['title'] . '</td> ' . "\n" . '<td class="order-totals-num" align="right" nowrap="nowrap">' .($order_totals[$i]['text']) .'</td> </tr>' . "\n" . '<tr>';
    }
    $html_msg['ORDER_TOTALS'] = '<table border="0" width="100%" cellspacing="0" cellpadding="2"> ' . $html_ot . ' </table>';
 
    //addresses area: Delivery
    $html_msg['HEADING_ADDRESS_INFORMATION']= HEADING_ADDRESS_INFORMATION;
    $html_msg['ADDRESS_DELIVERY_TITLE']     = EMAIL_TEXT_DELIVERY_ADDRESS;
    if(empty($this->delivery)){
        $html_msg['ADDRESS_DELIVERY_DETAIL']    = ($this->content_type != 'virtual') ? zen_address_label($_SESSION['customer_id'], $_SESSION['sendto'], true, '', "<br />") : 'n/a';
    }else{
        $delivery = $this->delivery;
        $html_msg['ADDRESS_DELIVERY_DETAIL'] = $delivery['company'] . "<br />" . $delivery['name'] . "<br />" . $delivery['suburb'] . " " . $delivery['street_address'] . "<br />" .  $delivery['city'] . ", " . $delivery['postcode'] . "<br />" . $delivery['state'] . ", " . $delivery['country'];
    }
    $html_msg['SHIPPING_METHOD_TITLE']      = HEADING_SHIPPING_METHOD;
    $html_msg['SHIPPING_METHOD_DETAIL']     = (zen_not_null($this->info['shipping_method'])) ? $this->info['shipping_method'] : 'n/a';
 
    if ($this->content_type != 'virtual') {
      $email_order .= "\n" . EMAIL_TEXT_DELIVERY_ADDRESS . "\n" .
      EMAIL_SEPARATOR . "\n" .
      zen_address_label($_SESSION['customer_id'], $_SESSION['sendto'], 0, '', "\n") . "\n";
    }
 
    //addresses area: Billing
    $email_order .= "\n" . EMAIL_TEXT_BILLING_ADDRESS . "\n" .
    EMAIL_SEPARATOR . "\n" .
    zen_address_label($_SESSION['customer_id'], $_SESSION['billto'], 0, '', "\n") . "\n\n";
    $html_msg['ADDRESS_BILLING_TITLE']   = EMAIL_TEXT_BILLING_ADDRESS;
    if(empty($this->billing)){
        $html_msg['ADDRESS_BILLING_DETAIL']  = zen_address_label($_SESSION['customer_id'], $_SESSION['billto'], true, '', "<br />");
    }else{
        $billing = $this->billing;
        $html_msg['ADDRESS_BILLING_DETAIL'] = $billing['company'] . "<br />" . $billing['name'] . "<br />" . $billing['suburb'] . " " . $billing['street_address'] . "<br />" .  $billing['city'] . ", " . $billing['postcode'] . "<br />" . $billing['state'] . ", " . $billing['country'];
    }
 
    if (is_object($GLOBALS[$_SESSION['payment']])) {
      $cc_num_display = (isset($this->info['cc_number']) && $this->info['cc_number'] != '') ? /*substr($this->info['cc_number'], 0, 4) . */ str_repeat('X', (strlen($this->info['cc_number']) - 8)) . substr($this->info['cc_number'], -4) . "\n\n" : '';
      $email_order .= EMAIL_TEXT_PAYMENT_METHOD . "\n" .
      EMAIL_SEPARATOR . "\n";
      $payment_class = $_SESSION['payment'];
      $email_order .= $GLOBALS[$payment_class]->title . "\n\n";
      $email_order .= (isset($this->info['cc_type']) && $this->info['cc_type'] != '') ? $this->info['cc_type'] . ' ' . $cc_num_display . "\n\n" : '';
      $email_order .= ($GLOBALS[$payment_class]->email_footer) ? $GLOBALS[$payment_class]->email_footer . "\n\n" : '';
    } else {
      $email_order .= EMAIL_TEXT_PAYMENT_METHOD . "\n" .
      EMAIL_SEPARATOR . "\n";
      $email_order .= PAYMENT_METHOD_GV . "\n\n";
    }
    $html_msg['PAYMENT_METHOD_TITLE']  = EMAIL_TEXT_PAYMENT_METHOD;
    $html_msg['PAYMENT_METHOD_DETAIL'] = (is_object($GLOBALS[$_SESSION['payment']]) ? $GLOBALS[$payment_class]->title : PAYMENT_METHOD_GV );
    $html_msg['PAYMENT_METHOD_FOOTER'] = (is_object($GLOBALS[$_SESSION['payment']]) && $GLOBALS[$payment_class]->email_footer != '') ? nl2br($GLOBALS[$payment_class]->email_footer) : (isset($this->info['cc_type']) && $this->info['cc_type'] != '' ? $this->info['cc_type'] . ' ' . $cc_num_display . "\n\n" : '');
 
    // include disclaimer
    if (defined('EMAIL_DISCLAIMER') && EMAIL_DISCLAIMER != '') $email_order .= "\n-----\n" . sprintf(EMAIL_DISCLAIMER, STORE_OWNER_EMAIL_ADDRESS) . "\n\n";
    // include copyright
    if (defined('EMAIL_FOOTER_COPYRIGHT')) $email_order .= "\n-----\n" . EMAIL_FOOTER_COPYRIGHT . "\n\n";
 
    while (strstr($email_order, '&nbsp;')) $email_order = str_replace('&nbsp;', ' ', $email_order);
 
    if(!empty($this->customer['firstname'])){
        $html_msg['EMAIL_FIRST_NAME'] = $this->customer['firstname'];
        $html_msg['EMAIL_LAST_NAME'] = $this->customer['lastname'];
    }elseif($this->customer['name']){
        $html_msg['EMAIL_FIRST_NAME'] = $this->customer['name'];
        $html_msg['EMAIL_LAST_NAME'] = '';
    }
    //  $html_msg['EMAIL_TEXT_HEADER'] = EMAIL_TEXT_HEADER;
    $html_msg['EXTRA_INFO'] = '';
    $this->notify('NOTIFY_ORDER_INVOICE_CONTENT_READY_TO_SEND', array('zf_insert_id' => $zf_insert_id, 'text_email' => $email_order, 'html_email' => $html_msg));
    zen_mail($this->customer['firstname'] . ' ' . $this->customer['lastname'], $this->customer['email_address'], EMAIL_TEXT_SUBJECT . EMAIL_ORDER_NUMBER_SUBJECT . zen_get_order_orders_number($zf_insert_id), $email_order, STORE_NAME, EMAIL_FROM, $html_msg, 'checkout', $this->attachArray);
 
    // send additional emails
    if (SEND_EXTRA_ORDER_EMAILS_TO != '') {
      $extra_info=email_collect_extra_info('','', $this->customer['firstname'] . ' ' . $this->customer['lastname'], $this->customer['email_address'], $this->customer['telephone']);
      $html_msg['EXTRA_INFO'] = $extra_info['HTML'];
 
      // include authcode and transaction id in admin-copy of email
      if ($GLOBALS[$_SESSION['payment']]->auth_code || $GLOBALS[$_SESSION['payment']]->transaction_id) {
        $pmt_details = ($GLOBALS[$_SESSION['payment']]->auth_code != '' ? 'AuthCode: ' . $GLOBALS[$_SESSION['payment']]->auth_code . '  ' : '') . ($GLOBALS[$_SESSION['payment']]->transaction_id != '' ?  'TransID: ' . $GLOBALS[$_SESSION['payment']]->transaction_id : '') . "\n\n";
        $email_order = $pmt_details . $email_order;
        $html_msg['EMAIL_TEXT_HEADER'] = nl2br($pmt_details) . $html_msg['EMAIL_TEXT_HEADER'];
      }
 
      zen_mail('', SEND_EXTRA_ORDER_EMAILS_TO, SEND_EXTRA_NEW_ORDERS_EMAILS_TO_SUBJECT . ' ' . EMAIL_TEXT_SUBJECT . EMAIL_ORDER_NUMBER_SUBJECT . zen_get_order_orders_number($zf_insert_id),
      $email_order . $extra_info['TEXT'], STORE_NAME, EMAIL_FROM, $html_msg, 'checkout_extra', $this->attachArray);
    }
    $this->notify('NOTIFY_ORDER_AFTER_SEND_ORDER_EMAIL', array($zf_insert_id, $email_order, $extra_info, $html_msg));
  }
 
}

11. 未付款订单不需要永久保存,我们规定未付款订单超过三天自动删除,而且未付款订单在生成半小时后,或距离删除时间还有12小时的时候,都会自动发送一封邮件给客户,提醒他及时付款,以及订单将被删除。现在需要在订单表 orders 中增加 payment_reminder, delete_reminder两个字段,类型为TINYINT,用0或1表示发送和未发送,在 includes/init_includes 中增加一个文件,或者在 includes/init_includes 目录下的某个文件中添加代码都可以。我是在 init_special_funcs.php 这个文件末尾增加代码,因为当网站被点击一次,这些代码将会被执行一次,其实完全没必要,所以使用了 if(rand(1,10) == 5) 这个方法来限制代码执行次数,如果你的PV量越大,随机数设置就要相应的大些即可。代码如下:

if(rand(1,10) == 5){
    $unpaid_order = "select orders_id, orders_num, customers_name, customers_email_address, payment_reminder, delete_reminder, date_purchased from " . TABLE_ORDERS . " where orders_status = 11";
    $unpaid_order = $db->Execute($unpaid_order);
    while (!$unpaid_order->EOF) {
        $now=date("Y-m-d H:i:s");
        $delete_order = date("Y-m-d H:i:s",strtotime("+3days",strtotime($unpaid_order->fields['date_purchased'])));
        $payment_reminder = date("Y-m-d H:i:s",strtotime("+5Minute",strtotime($unpaid_order->fields['date_purchased'])));
        $delete_reminder = date("Y-m-d H:i:s",strtotime("+60Hour",strtotime($unpaid_order->fields['date_purchased'])));
        
        if($now > $delete_order){
                $db->Execute("delete from " . TABLE_ORDERS . " where orders_id = '" . (int)$unpaid_order->fields['orders_id'] . "'");
                $db->Execute("delete from " . TABLE_ORDERS_PRODUCTS . "
                              where orders_id = '" . (int)$unpaid_order->fields['orders_id'] . "'");
            
                $db->Execute("delete from " . TABLE_ORDERS_PRODUCTS_ATTRIBUTES . "
                              where orders_id = '" . (int)$unpaid_order->fields['orders_id'] . "'");
            
                $db->Execute("delete from " . TABLE_ORDERS_PRODUCTS_DOWNLOAD . "
                              where orders_id = '" . (int)$unpaid_order->fields['orders_id'] . "'");
            
                $db->Execute("delete from " . TABLE_ORDERS_STATUS_HISTORY . "
                              where orders_id = '" . (int)$unpaid_order->fields['orders_id'] . "'");
            
                $db->Execute("delete from " . TABLE_ORDERS_TOTAL . "
                              where orders_id = '" . (int)$unpaid_order->fields['orders_id'] . "'");
        }
        
        if($unpaid_order->fields['payment_reminder'] == 0 && $now > $payment_reminder){
            $to_name = $unpaid_order->fields['customers_name'];
            $to_address = $unpaid_order->fields['customers_email_address'];
            $email_subject="Your Pending Order No: " . $unpaid_order->fields['orders_num'];
            $email_text='<p>Dear '.$unpaid_order->fields['customers_name'].',<br /></p>
                         <p>Thanks for choosing Geeetech, your order has been generated, however, we are still waiting for your payment, please finish the payment timely.</p>
                         <p>We will keep your order  for 3 days, during that time, you can continue to pay at my order on www.geeetech.com.</p>
                         <p>If you do not pay in 3 days, your order will be deleted automatically, If there is any problem during the payment, please let us know as soon as possible.</p>
                         <p>
                         <a href="'.zen_href_link(FILENAME_ACCOUNT_HISTORY).'" style="height:30px; line-height:30px; border:1px #000 solid; display:block; width:100px; text-align:center; background:#ccc;">Check My Order</a>
                         &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
                         <a href="'.zen_href_link(FILENAME_ACCOUNT_HISTORY_INFO,"order_id=".$unpaid_order->fields["orders_id"]).'" style="height:30px; line-height:30px; border:1px #000 solid; display:block; width:100px; text-align:center; background:#ccc;">Pay Now</a>
                         </p>
                        ';
            $block=array("EMAIL_MESSAGE_HTML" => $email_text);
            zen_mail($to_name, $to_address, $email_subject, $email_text, STORE_NAME, EMAIL_FROM, $block);
            $db->Execute("update " . TABLE_ORDERS . "
                          set payment_reminder = 1 
                          where orders_id = '" . (int)$unpaid_order->fields['orders_id'] . "'");
        }
        
        if($unpaid_order->fields['delete_reminder'] == 0 && $now > $delete_reminder){
            $to_name = $unpaid_order->fields['customers_name'];
            $to_address = $unpaid_order->fields['customers_email_address'];
            $email_subject="Your Pending Order No: " . $unpaid_order->fields['orders_num'];
            $email_text='<p>Dear '.$unpaid_order->fields['customers_name'].',<br /></p>
                         <p>You have placed an order at Geeetech on ' . strftime(DATE_TIME_FORMAT,strtotime($unpaid_order->fields['date_purchased'])) .' [-0600GMT], however, we are still waiting for your payment. </p>
                         <p>Your order will be deleted automatically in 12 hours,  please finish the payment timely. If there is any problem during the payment, please let us know as soon as possible. </p>
                         </p>
                         <a href="'.zen_href_link(FILENAME_ACCOUNT_HISTORY).'" style="height:30px; line-height:30px; border:1px #000 solid; display:block; width:100px; text-align:center; background:#ccc;">Check My Order</a>
                         &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
                         <a href="'.zen_href_link(FILENAME_ACCOUNT_HISTORY_INFO,"order_id=".$unpaid_order->fields["orders_id"]).'" style="height:30px; line-height:30px; border:1px #000 solid; display:block; width:100px; text-align:center; background:#ccc;">Pay Now</a>
                         </p>
                        ';
            $block=array("EMAIL_MESSAGE_HTML" => $email_text);
            zen_mail($to_name, $to_address, $email_subject, $email_text, STORE_NAME, EMAIL_FROM, $block);
            $db->Execute("update " . TABLE_ORDERS . "
                          set delete_reminder = 1
                          where orders_id = '" . (int)$unpaid_order->fields['orders_id'] . "'");
        }
        
        $unpaid_order->MoveNext();
    }
    
    $special_count = "select specials_id, specials_date_available from " . TABLE_SPECIALS . " where specials_date_available > '" . date('Y-m-d') . "' and counter > 0";
    $special_count = $db->Execute($special_count);
    while(!$special_count->EOF){
        $update_specials = "update " . TABLE_SPECIALS . " set counter = 0 where specials_id = ". $special_count->fields['specials_id'];
        $db->Execute($update_specials);
        $special_count->MoveNext();
    }
}

经过上面的修改,我们的流程如下:

1. 购物车(shopping cart)

2. [货运方式(delivery method)]

3. 支付方式(payment method)

4. 订单确认(confirmation)  

5. 订单处理(checkout process)

6. 下单成功(checkout success)

7. [第三方网站支付] 

因为从订单确认到订单处理,都是在我们自己的网站完成的,并且进入支付网站之前,订单已经存在了,这样就不会出现漏单的情况了。

在测试过程中,我们不可能直接使用自己的Paypal去测试订单,这样手续费都要扣很大部分,Paypal为了给IT人员测试接口,开发了虚拟Paypal帐号,可以通过Paypal虚拟帐号测试功能。具体申请使用教程链接如下:http://blog.sina.com.cn/s/blog_7285f5d30101fq05.html

总结:

以上修改,完成了网站四个新功能。

1. 快速支付功能

2. 先生成订单后付款功能

3. 按指定时间自动删除未付款订单以及自动发送提示邮件功能

4. 实现和淘宝一样,后台修改未付款订单价格功能

最后:可能还有些代码细节没有一一说到,但是上传的这些代码里面都有体现,需要自己仔细看。有什么问题可以给我留言!

 

(责任编辑:最模板)
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
栏目列表
热点内容