Anyone who has used zen-cart knows that the Order steps in zen-cart are as follows ([] indicates that they are not required ):
1. shopping cart)
2. [freight method]
3. payment method)
4. confirm the order (confirmation)
5. [Third-Party website payment]
6. Order Processing (checkout process) -- this step is important because the information in the shopping cart is written to the order.
7. The order is successfully placed (checkout success)
Such a process is normal. However, during the process from step 1 to step 2, the user may close the webpage directly if the payment is successful, or cannot jump to the checkout_process page due to network reasons, the consequence is that the order cannot be created normally.
Based on the above analysis, we hope to slightly change the process, that is, the Order has been created before the payment, so that even if the payment cannot be redirected back from the third-party payment website, we will not see the user's payment is successful but there is no order in the background. The modified blueprint is basically as follows:
1. After confirming the order on the checkour_confirmation page, the system will directly proccess and go to the checkour_success page, where you can go to the payment page. As shown in:
2. If the customer fails to pay at the time, he can go to his background to make payment for the historical order. As shown in:
Next, let's take a look at how to implement the above functions step by step.
1. First, we need to transform the existing payment module. You need to add the paynow_action_url field to the class of the payment method to indicate the page url for the payment. You also need to add a function, paynow_button ($ order_id ), to obtain the parameter hidden domain code of the payment form.
To add the paynow_action_url field, add the following code in the constructor of the payment class:
Copy codeThe Code is as follows: 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;
}
To add the paynow_button ($ order_id) function, add the following code after the last function of the payment class:Copy codeThe Code is as follows: 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. Use the paypal payment method as an example to describe how to implement it. In order not to destroy the original code of paypal, we copied a copy of The paypal. php file and named it paypalsimple. php, and modified the code. The Code is as follows. We can see that the form_action_url is removed and the paynow_action_url is given. Because we want users to click "Confirm order" and directly enter checkout_process, if form_action_url is not specified, then the form for confirming the order will be directly submitted to the checkout_process page, and paynow_action_url is the previous value of form_action_url. The implementation of the paynow_button function is also very simple. Here we just cut the content of the original process_button () function, but we didn't use the global $ order variable, instead, you can use $ order = new order ($ order_id) to reconstruct an object to prepare for displaying the pay now button in the History order.
Paypalsimple. phpCopy codeThe Code is as follows: <? Php
/**
* @ Package paypalsimple payment 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). 'payment/paypal/paypal_functions.php ');
Class paypalsimple {
Var $ code, $ title, $ description, $ enabled;
// Class constructor
Function paypalsimple (){
Global $ order;
$ This-> 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'] <1 ){
$ 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 compute cript_validation (){
Return false;
}
Function selection (){
$ Text = MODULE_PAYMENT_SIMPLE_PAYPAL_TEXT_CATALOG_LOGO. ''. MODULE_PAYMENT_PAYPAL_SIMPLE_TEXT_TITLE. '<br/> <span class = "smallText"> '. MODULE_PAYMENT_PAYPAL_SIMPLE_ACCEPTANCE_MARK_TEXT. '</span> <br/> ';
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 ". 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 _ upload', 'true ', 'Do you want to accept PayPal-Simple payments? ', '6', '0', 'zen _ performance_select_option (array (\ 'true \', \ 'false \ '),', now ())");
$ Db-> Execute ("insert ". 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 ". 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 _ upload', '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 ". 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 _ upload', '0 ', 'set the status of orders made with this payment module to this value', '6', '0', 'zen _ zhang_pull_down_order_statuses (', 'zen _ get_order_status_name ', now ())");
$ Db-> Execute ("insert ". 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/> 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> response </code> ', '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 _ detail', '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 ['telphone']);
If ($ telephone! = ''){
$ OptionsPhone ['h _ phonenumber'] = $ telephone;
If (in_array ($ order-> customer ['country'] ['iso _ code_2 '], array ('us', 'CA '))){
$ OptionsPhone ['ight _ phone_a '] = substr ($ telephone, 0, 3 );
$ OptionsPhone ['ight _ phone_ B '] = substr ($ telephone, 3, 3 );
$ OptionsPhone ['ight _ 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 ['ight _ 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 '),
'Cel _ return '=> zen_href_link (FILENAME_PAY_FAILED, '', 'ssl '),
'Shopping _ url' => zen_href_link (FILENAME_SHOPPING_CART, '', 'ssl '),
'Your Y _ 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']),
'Address' => 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 ['burb']! = '') $ OptionsCust ['ssss2'] = $ order-> customer ['burb'];
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); $ I <$ n; $ I ++ ){
If (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 <$ 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 ('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. The pay now button is displayed on the checkout_success page. Open the file "maid/modules/pages/checkout_success/header. php ", add the following code at the end of the file (if you have mastered the notification/Observer mode in zen-cart and do not want to destroy the core zen-cart code, you can also create an observation class to listen to yy_header_end_checkout_success ).Copy codeThe Code is as follows: require_once (DIR_WS_CLASSES. 'order. php ');
Require_once (DIR_WS_CLASSES. 'payment. php ');
$ Payment_modules = new payment ($ orders-> fields ['payment _ module_code ']);
Open the file "des/modules/templates/template_default/templates/tpl_checkout_success_default.php", and add the following code to the appropriate location. Here, you have made a judgment on the order status, this button is displayed only when the order status is unpaid,Copy codeThe Code is as follows: <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. display the pay now button in the History Order. There are three pages for displaying the pay now button: account, account_history, and account_history_info. The implementation here is similar to the implementation of the checkout_success page, but the parameters passed to the $ payment_modules function paynow_button are different, I will not go into details here.
Summary:
After the above modification, our process is as follows:
1. shopping cart)
2. [freight method]
3. payment method)
4. confirm the order (confirmation)
5. Order Processing (checkout process)
6. The order is successfully placed (checkout success)
7. [Third-Party website payment]
From order confirmation to order processing, the order is completed on our own website, and before entering the payment website, the order already exists, so that the order will not be dropped.