1. 购物车(shopping cart)
2. [货运方式(delivery method)]
4. 订单确认(confirmation)
5. [第三方网站支付]
基于上述的分析, 我们希望稍微地改变一下流程,即在支付之前订单已经创建好了,这样就算在支付时不能从第三方支付网站跳转回来,我们也不会存在用户付款成功却在后台没有订单的情况了。经过修改后的蓝图基本是下面这样的:
2. 如果当时客户没能付款,也可进入自己的后台对历史订单进行付款。如下图所示:
1. 首先我们需要对现有的支付模块进行一个改造。需要对支付方式的class增加一个字段paynow_action_url,用来表示进行支付的页面url,另外还需要增加一个函数,paynow_button($order_id),来获取支付表单的参数隐藏域代码。
要增加paynow_action_url字段,请在类payment的构造函数中最后加上下面的代码:
2. 以paypal支付方式为例子,说明如何具体实现。为了不破坏paypal原有的代码,我们将paypal@R_
_7780@拷贝一个副本出来,并命名为paypalsimple.
,并对里面的代码做适当的修改。代码如下所示,可以看到,这里去掉了对form_action_url的指定,并给定了paynow_action_url,因为我们希望用户点击“确认订单”后直接进入
kout_process页面了,而paynow_action_url就是以前的form_action_url的值。paynow_button函数的实现也很简单,这里只是将原先的process_button()函数的内容剪切过来而已,
使用全局的$order变量,而是使用$order = new order($order_id),来重新构造的一个对象,这样做是为在历史订单中显示pay now按钮做准备的。
paypalsimple.
php /
** * @package paypalsimple pa
yment module
* @copyright Copyright 2003-2006 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: paypalsimple.
php 4960 2009-12-29 11
:46
:46Z gary $
*/
// ensure dependencies are loaded
include_once((IS_ADMIN_FLAG === true ? DIR_FS_CATALOG_MODULES : DIR_WS_MODULES) . 'pa
yment/paypal/paypal_function
s.php'
); class paypalsimple
{ var $code,$
title,$description,$enabled;
// class constructor
function paypalsimple()
{ global $order;
$this->code = 'paypalsimple';
$this->
title = MODULE_PA
ymENT_PAYPAL_SIMPLE_TEXT_
titlE;
if(IS_ADMIN_FLAG === tru
E){ $this->
title = MODULE_PA
ymENT_PAYPAL_SIMPLE_TEXT_ADMIN_
titlE;
}
$this->description = MODULE_PA
ymENT_PAYPAL_SIMPLE_TEXT_DESCRIPTION;
$this->sort_order = MODULE_PA
ymENT_PAYPAL_SIMPLE_SORT_ORDER;
$this->enabled = ((MODULE_PA
ymENT_PAYPAL_SIMPLE_STATUS == 'True') ? true :
fals
E);
if ((
int)R_578_11845@ODULE_PA
ymENT_PAYPAL_SIMPLE_ORDER_STATUS_ID > 0)
{ $this->order_status = MODULE_PA
ymENT_PAYPAL_SIMPLE_ORDER_STATUS_ID;
}
$this->paynow_action_url = '
https://' . MODULE_PA
ymENT_PAYPAL_SIMPLE_HANDLER;
if (is_ob
ject($order)) $this->
update_status(
); }
// class methods
function
update_status()
{ global $order,$db;
if ( ($this->enabled == tru
E) && ((
int)R_578_11845@ODULE_PA
ymENT_PAYPAL_SIMPLE_ZONE > 0) )
{ $
check_flag =
false;
$
check = $db->Execute("
SELEct zone_id from " . TABLE_ZO
nes_TO_GEO_ZO
nes . " where geo_zone_id = '" . MODULE_PA
ymENT_PAYPAL_SIMPLE_ZONE . "' and zone_country_id = '" . $order->billing['country']['id'] . "' order by zone_id"
); while (!$
check->EOF)
{ if ($
check->fields['zone_id'] < 1)
{ $
check_flag = true;
break;
} elseif ($
check->fields['zone_id'] == $order->billing['zone_id'])
{ $
check_flag = true;
break;
}
$
check->MoveNext(
); }
if ($
check_flag ==
fals
E) { $this->enabled =
false;
}
}
}
function javascript_validation()
{ return
false;
}
function
SELEction()
{ $text = MODULE_PA
ymENT_SIMPLE_PAYPAL_TEXT_CATALOG_LOGO.''.MODULE_PA
ymENT_PAYPAL_SIMPLE_TEXT_
titlE . '
smallText">' . MODULE_PAymENT_PAYPAL_SIMPLE_ACCEPTANCE_MARK_TEXT . '';
return array('id' => $this->code,
'module' => $text
); }
function pre_confirmation_
check()
{ return
false;
}
function confirmation()
{ return
false;
}
function process_button()
{ return
false;
}
function before_process()
{ return
false;
}
function after_process()
{ return
false;
}
function get_error()
{ return
false;
}
function
check()
{ global $db;
if (!isset($this->_
check))
{ $
check_query = $db->Execute("
SELEct configuration_value from " . TABLE_CONFIGURATION . " where configuration_key = 'MODULE_PA
ymENT_PAYPAL_SIMPLE_STATUS'"
); $this->_
check = $
check_query->RecordCount(
); }
return $this->_
check;
}
function install()
{ global $db;
$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-Simple Module','MODULE_PA
ymENT_PAYPAL_SIMPLE_STATUS','True','Do
you want to accept PayPal-Simple pa
yments?','6','0','zen_cfg_
SELEct_option(array(\'True\',\'
false\'),',now())"
); $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_
title,date_added) values ('Sort order of display.','MODULE_PA
ymENT_PAYPAL_SIMPLE_SORT_ORDER','Sort order of display. Lo
West is displayed first.','8',use_function,date_added) values ('Pa
yment Zone','MODULE_PA
ymENT_PAYPAL_SIMPLE_ZONE','If a zone is
SELEcted,only enable this pa
yment method for that zone.','2','zen_get_zone_class_
title','zen_cfg_pull_down_zone_classes(',date_added) values ('Set Order Status','MODULE_PA
ymENT_PAYPAL_SIMPLE_ORDER_STATUS_ID','Set the status of
orders made with this pa
yment module to this value','zen_cfg_pull_down_order_statuses(','zen_get_order_status_name',date_added) values ('Mode for PayPal web
services
Default:
www.paypal.com/cgi-bin/webscr
or
www.paypal.com/us/cgi-bin/webscr
or for the UK,
www.paypal.com/uk/cgi-bin/webscr
','MODULE_PA
ymENT_PAYPAL_SIMPLE_HANDLER','www.paypa
l.com/cgi-bin/webscr','Choose the URL for PayPal live processing','73','',now())"
); }
function remove()
{ global $db;
$db->Execute("
delete from " . TABLE_CONFIGURATION . " where configuration_key in ('" . implode("','",$this->keys()) . "')"
); }
function keys()
{ return array('MODULE_PA
ymENT_PAYPAL_SIMPLE_STATUS','MODULE_PA
ymENT_PAYPAL_SIMPLE_HANDLER'
); }
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->@R_749_1
0586@lsum = $order->info['@R_749_1
0586@l'];
// save the session
stuff pe
RMANently 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,expir
y) 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(
); $this->
transaction_currency = $my_currency;
$this->
transaction_
amount = ($this->@R_749_1
0586@lsum * $currencies->get_value($my_currency)
); $telephone = preg_
replace('/\D/',$order->customer['telephone']
); if ($telephone
!= '')
{ $optionsPhone['H_Phone
number'] = $telephone;
if (in_array($order->customer['country']['iso_code_2'],array('US','CA')))
{ $optionsPhone['night_phone_a'] = substr($telephone,3
); $optionsPhone['night_phone_b'] = substr($telephone,3,3
); $optionsPhone['night_phone_c'] = substr($telephone,6,4
); $optionsPhone['day_phone_a'] = substr($telephone,3
); $optionsPhone['day_phone_b'] = substr($telephone,3
); $optionsPhone['day_phone_c'] = substr($telephone,4
); } else
{ $optionsPhone['night_phone_b'] = $telephone;
$optionsPhone['day_phone_b'] = $telephone;
}
}
$optionsCore = array(
'charset' => CHARSET,
'lc' => $order->customer['country']['iso_code_2'],
'page_style' => MODULE_PA
ymENT_PAYPAL_PAGE_STYLE,
'custom' => zen_session_name() . '=' . zen_session_id(),
'busi
ness' => MODULE_PA
ymENT_PAYPAL_BUSI
nesS_ID,
'return' => zen_href_link(FIL
ename_PAY_
succesS,'referer=paypal','SSL'),
'cancel_return' => zen_href_link(FIL
ename_PAY_FAILED,
'shopping_url' => zen_href_link(FIL
ename_SHOPPING_CART,
'notify_url' => zen_href_link('ipn_main_handler.
php','SSL',
false,tru
E),
'redirect_cmd' => '_xclick',
'rm' => 2,
'bn' => 'zencart',
'mrb' => 'R-6C7952342H795591R',
'pal' => '9E82WJBKKGPLQ',
); $optionsCust = array(
'firs
t_name' =>
replace_accents($order->customer['firstname']),
'las
t_name' =>
replace_accents($order->customer['lastname']),
'address1' =>
replace_accents($order->customer['stree
t_address']),
'city' =>
replace_accents($order->customer['city']),
'state' => zen_get_zone_code($order->customer['country']['id'],$order->customer['zone_id'],$order->customer['zone_id']),
'zip' => $order->customer['postcode'],
'country' => $order->customer['country']['iso_code_2'],
'email' => $order->customer['email_address'],
); if ($order->customer['suburb']
!= '') $optionsCust['address2'] = $order->customer['suburb'];
if (MODULE_PA
ymENT_PAYPAL_ADDRESS_
requIRED == 2) $optionsCust = array(
'address_name' =>
replace_accents($order->customer['firstname'] . ' ' . $order->customer['lastname']),
'address_street' =>
replace_accents($order->customer['stree
t_address']),
'address_city' =>
replace_accents($order->customer['city']),
'address_state' => zen_get_zone_code($order->customer['country']['id'],
'address_zip' => $order->customer['postcode'],
'address_country' => $order->customer['country']['
title'],
'address_country_code' => $order->customer['country']['iso_code_2'],
'payer_email' => $order->customer['email_address'],
); $optionsShip = array(
//'address_override' => MODULE_PA
ymENT_PAYPAL_ADDRESS_OVERRIDE,
'no_shipping' => MODULE_PA
ymENT_PAYPAL_ADDRESS_
requIRED,
); if (MODULE_PA
ymENT_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']
); }
if (isset($optionsLineItems['handling']))
{ $optionsLineItems['handling_1'] = $optionsLineItems['handling'];
unset($optionsLineItems['handling']
); }
unset($optionsLineItems['sub@R_749_1
0586@l']
); // if line-item details couldn't be kept due to calculation mi
smatches or discounts etc,default to aggregate mode
if (!isset($optionsLineItems['item_name_1'])) $optionsLineItems = array(
); //if ($optionsLineItems['
amount']
!= $this->
transaction_
amount) $optionsLineItems = array(
); ipn_debug_email('Line Item Details (if blank,this means there was a data mi
smatch,
and thus bypassed): ' . "\n" . print_r($optionsLineItems,tru
E)); }
$produc
ts_name_display = "";
/*
for ($i
=0,$n=sizeof($order->products
); $i<$n; $i++)
{ if(i > 0)
{ $produc
ts_name_display.= ',';
}
$produc
ts_name_display.= $order->products[$i]['name']. '('. $order->products[$i]['qty'] .','.$order->products[$i]['dhisys_web_
order_number'].')';
}*/
$optionsAggregate = array(
'cmd' => '_ext-enter',
'item_name' => $produc
ts_name_display,
'item_
number' => $order_id,
'num_cart_items' => sizeof($order->products),
'
amount' =>
number_format($this->
transaction_
amount,$currencies->get_
decimal_places($my_currency)),
'shipping' => '0.00',
); if (MODULE_PA
ymENT_PAYPAL_TAX_OVERRIDE == 'true') $optionsAggregate['tax'] = '0.00';
if (MODULE_PA
ymENT_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,$optionsAggregat
E);
ipn_debug_email('Keys for submission: ' . print_r($options,tru
E)); if(sizeof($order->products) > 0)
{ $options['cmd'] = '_cart';
for ($i
=0,$n=sizeof($order->products
); $i<$n; $i++)
{ $options['item_name_'. (
String)($i+1)] = $order->products[$i]['name'];
$options['item_
number_'. (
String)($i+1)] = $order->products[$i]['dhisys_web_
order_number'];
$options['
amount_'. (
String)($i+1)] =
number_format((float)$order->products[$i]['final_price'],2
); $options['quantity_'. (
String)($i+1)] = $order->products[$i]['qty'];
}
}
// 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('data
check - ABOR
TinG - preg_match found invalid submission key: ' . $name . ' (' . $value . ')'
); break;
}
// do we need special handling for & and = s
ymbols?
//if (strpos($value,'&')
!==
false || strpos($value,'=')
!==
fals
E) $value = urlencode($
value);
$buttonArra
Y[] = zen_draw_hidden_field($name,$
value);
}
$_SESSION['paypal_
transaction_info'] = array($this->
transaction_
amount,$this->
transaction_currency
); $process_button_
String = implode("\n",$buttonArray) . "\n";
return $process_button_
String;
}
}
?>
3. 在
s/header.
s_default.
4. 在历史订单中显示pay now按钮。需要显示pay now按钮的页面有三个:account,
1. 购物车(shopping cart)
2. [货运方式(delivery method)]
3. 支付方式(pa
4. 订单确认(confirmation)
5. 订单处理(
6. 下单成功(
7. [第三方网站支付]