zen-cart进入第三方支付网站后,如果不能正常返回,则会造成客户已付款但后台却无订单数据的尴尬局面。本文就针对该问题给出一种解决方案,希望对被同样问题困扰的同行有所帮助。 用过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
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",并在适当的位置加上如下的代码,这里对订单的状态进行了一个判断,当只有订单的状态在未付款状态,才显示该按钮,
<div id="pay_now">
<?php //&& $orders->fields['orders_status'] == '1' if(isset($payment_modules->paynow_action_url) && $payment_modules->paynow_action_url != ''&& $orders->fields['orders_status'] == '1'){ echo('<fieldset id="csNotifications">'); echo('<legend>'.TEXT_PAYNOW.'</legend>'); echo zen_draw_form('checkout_paynow', $payment_modules->paynow_action_url, 'post', 'id="checkout_confirmation" onsubmit="submitonce();"'); $selection = $payment_modules->selection(); echo('<div class="buttonRow payment_method">'.$selection[0]['module'].'</div>'); echo('<div class="buttonRow forward paynow">'); 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('</div>'); echo('</form>'); echo('</fieldset>'); } ?> </div> 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. [第三方网站支付] 因为从订单确认到订单处理,都是在我们自己的网站完成的,并且进入支付网站之前,订单已经存在了,这样就不会出现掉单的情况了。(责任编辑:最模板) |