您好,欢迎访问一九零五行业门户网

php 修改zen-cart下单和付款流程以防止漏单_PHP教程

用过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页面,这样造成的后果是很严重的,因为订单不能被正常的创建。
基于上述的分析, 我们希望稍微地改变一下流程,即在支付之前订单已经创建好了,这样就算在支付时不能从第三方支付网站跳转回来,我们也不会存在用户付款成功却在后台没有订单的情况了。经过修改后的蓝图基本是下面这样的:
1. 在checkour_confirmation页面确认订单后,都会直接proccess,并且进入checkour_success页面,可以在这里进入付款页面。如下图所示:
2. 如果当时客户没能付款,也可进入自己的后台对历史订单进行付款。如下图所示:
下面我们就来看看如何一步一步来实现上述的功能。
  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原有的代码,我们将paypal.php文件拷贝一个副本出来,并命名为paypalsimple.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按钮做准备的。
paypalsimple.php
复制代码 代码如下:
code = 'paypalsimple';
$this->title = module_payment_paypal_simple_text_title;
if(is_admin_flag === true){
$this->title = module_payment_paypal_simple_text_admin_title;
}
$this->description = module_payment_paypal_simple_text_description;
$this->sort_order = module_payment_paypal_simple_sort_order;
$this->enabled = ((module_payment_paypal_simple_status == 'true') ? true : false);
if ((int)module_payment_paypal_simple_order_status_id > 0) {
$this->order_status = module_payment_paypal_simple_order_status_id;
}
$this->paynow_action_url = 'https://' . module_payment_paypal_simple_handler;
if (is_object($order)) $this->update_status();
}
// class methods
function update_status() {
global $order, $db;
if ( ($this->enabled == true) && ((int)module_payment_paypal_simple_zone > 0) ) {
$check_flag = false;
$check = $db->execute(select zone_id from . table_zones_to_geo_zones . where geo_zone_id = ' . module_payment_paypal_simple_zone . ' and zone_country_id = ' . $order->billing['country']['id'] . ' order by zone_id);
while (!$check->eof) {
if ($check->fields['zone_id'] $check_flag = true;
break;
} elseif ($check->fields['zone_id'] == $order->billing['zone_id']) {
$check_flag = true;
break;
}
$check->movenext();
}
if ($check_flag == false) {
$this->enabled = false;
}
}
}
function javascript_validation() {
return false;
}
function selection() {
$text = module_payment_simple_paypal_text_catalog_logo.'  '.module_payment_paypal_simple_text_title . '
' . 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_payment_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_payment_paypal_simple_status', 'true', 'do you want to accept paypal-simple 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 ('sort order of display.', 'module_payment_paypal_simple_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, use_function, set_function, date_added) values ('payment zone', 'module_payment_paypal_simple_zone', '0', 'if a zone is selected, only enable this payment method for that zone.', '6', '2', '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 order status', 'module_payment_paypal_simple_order_status_id', '0', 'set the status of orders made with this payment module to this value', '6', '0', '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, 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_payment_paypal_simple_handler', 'www.paypal.com/cgi-bin/webscr', 'choose the url for paypal live processing', '6', '73', '', now()));
}
function remove() {
global $db;
$db->execute(delete from . table_configuration . where configuration_key in (' . implode(', ', $this->keys()) . '));
}
function keys() {
return array('module_payment_paypal_simple_status','module_payment_paypal_simple_sort_order','module_payment_paypal_simple_zone','module_payment_paypal_simple_order_status_id', 'module_payment_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->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();
$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(
'charset' => charset,
'lc' => $order->customer['country']['iso_code_2'],
'page_style' => module_payment_paypal_page_style,
'custom' => zen_session_name() . '=' . zen_session_id(),
'business' => module_payment_paypal_business_id,
'return' => zen_href_link(filename_pay_success, 'referer=paypal', 'ssl'),
'cancel_return' => zen_href_link(filename_pay_failed, '', '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['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_payment_paypal_address_required == 2) $optionscust = array(
'address_name' => replace_accents($order->customer['firstname'] . ' ' . $order->customer['lastname']),
'address_street' => replace_accents($order->customer['street_address']),
'address_city' => replace_accents($order->customer['city']),
'address_state' => zen_get_zone_code($order->customer['country']['id'], $order->customer['zone_id'], $order->customer['zone_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_payment_paypal_address_override,
'no_shipping' => module_payment_paypal_address_required,
);
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']);
}
if (isset($optionslineitems['handling'])) {
$optionslineitems['handling_1'] = $optionslineitems['handling'];
unset($optionslineitems['handling']);
}
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 = array();
//if ($optionslineitems['amount'] != $this->transaction_amount) $optionslineitems = array();
ipn_debug_email('line item details (if blank, this means there was a data mismatch, and thus bypassed): ' . \n . print_r($optionslineitems, true));
}
$products_name_display = ;
/*
for ($i=0, $n=sizeof($order->products); $iif(i > 0) {
$products_name_display.= ', ';
}
$products_name_display.= $order->products[$i]['name']. '('. $order->products[$i]['qty'] .','.$order->products[$i]['dhisys_web_order_number'].')';
}*/
$optionsaggregate = array(
'cmd' => '_ext-enter',
'item_name' => $products_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_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));
if(sizeof($order->products) > 0){
$options['cmd'] = '_cart';
for ($i=0, $n=sizeof($order->products); $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('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);
}
$_session['paypal_transaction_info'] = array($this->transaction_amount, $this->transaction_currency);
$process_button_string = implode(\n, $buttonarray) . \n;
return $process_button_string;
}
}
?>
3. 在checkout_success页面中显示pay now按钮。打开文件includes/modules/pages/checkout_success/header.php,在文件的末尾添加下面的代码(如果你已经掌握zen-cart中的通知者/观察者模式,并且又不想破坏zen-cart核心代码的话,也可以创建一个观察类来监听notify_header_end_checkout_success来实现)。
复制代码 代码如下:
require_once(dir_ws_classes . 'order.php');
require_once(dir_ws_classes . 'payment.php');
$payment_modules = new payment($orders->fields['payment_module_code']);
打开文件includes/modules/templates/template_default/templates/tpl_checkout_success_default.php,并在适当的位置加上如下的代码,这里对订单的状态进行了一个判断,当只有订单的状态在未付款状态,才显示该按钮,
复制代码 代码如下:
fields['orders_status'] == '1'
if(isset($payment_modules->paynow_action_url) && $payment_modules->paynow_action_url != ''&& $orders->fields['orders_status'] == '1'){
echo('');
echo(''.text_paynow.'');
echo zen_draw_form('checkout_paynow', $payment_modules->paynow_action_url, 'post', 'id=checkout_confirmation onsubmit=submitonce();');
$selection = $payment_modules->selection();
echo(''.$selection[0]['module'].'
');
echo('');
if (is_array($payment_modules->modules)) {
echo $payment_modules->paynow_button($orders_id);
}
echo(zen_image_submit(button_image_paynow, button_image_paynow_alt, 'name=btn_paynow id=btn_paynow'));
echo('
');
echo('');
echo('');
}
?>
4. 在历史订单中显示pay now按钮。需要显示pay now按钮的页面有三个:account, account_history,account_history_info,这里的实现和checkout_success页面的实现大同小异,只是传给$payment_modules的函数paynow_button的参数不一样而已,这里就不再赘述。
总结:
经过上面的修改,我们的流程如下:
1. 购物车(shopping cart)
2. [货运方式(delivery method)]
3. 支付方式(payment method)
4. 订单确认(confirmation)
5. 订单处理(checkout process)
6. 下单成功(checkout success)
7. [第三方网站支付]
因为从订单确认到订单处理,都是在我们自己的网站完成的,并且进入支付网站之前,订单已经存在了,这样就不会出现掉单的情况了。
http://www.bkjia.com/phpjc/321347.htmlwww.bkjia.comtruehttp://www.bkjia.com/phpjc/321347.htmltecharticle用过zen-cart的人都知道,zen-cart中下单步骤是下面这样的(其中[]中的表示不是必须的): 1. 购物车(shopping cart) 2. [货运方式(delivery method)] 3. 支...
其它类似信息

推荐信息