generate_cart_hash(); /* Ok, need to decide if we have a free Shipping amount > 0, * and IF the cart total is more than that Free Shipping amount, * let's set Order Shipping = 0 */ $this->_subtotal = $this->get_order_subtotal($vars); if( $vendor_freeshipping > 0 && $vars['order_subtotal_withtax'] >= $vendor_freeshipping) { $PSHOP_SHIPPING_MODULES = Array( "free_shipping" ); include_once( CLASSPATH. "shipping/free_shipping.php" ); $this->_SHIPPING = new free_shipping(); } elseif( !empty( $_REQUEST['shipping_rate_id'] )) { // Create a Shipping Object and assign it to the _SHIPPING attribute // We take the first Part of the Shipping Rate Id String // which holds the Class Name of the Shipping Module $rate_array = explode( "|", urldecode(vmGet($_REQUEST,"shipping_rate_id")) ); $filename = basename( $rate_array[0] ); if( $filename != '' && file_exists(CLASSPATH. "shipping/".$filename.".php")) { include_once( CLASSPATH. "shipping/".$filename.".php" ); if( class_exists($filename) ) { $this->_SHIPPING = new $filename(); } } } //$steps = ps_checkout::get_checkout_steps(); if(empty($_REQUEST['ship_to_info_id']) && ps_checkout::noShipToNecessary()) { $db = new ps_DB(); /* Select all the ship to information for this user id and * order by modification date; most recently changed to oldest */ $q = "SELECT user_info_id from `#__{vm}_user_info` WHERE "; $q .= "user_id='" . $_SESSION['auth']["user_id"] . "' "; $q .= "AND address_type='BT'"; $db->query($q); $db->next_record(); $_REQUEST['ship_to_info_id'] = $db->f("user_info_id"); } } /** * Checks if Ship To can be skipped * * @return boolean */ function noShipToNecessary() { global $cart, $only_downloadable_products; if( NO_SHIPTO == '1') { return true; } if( !isset( $cart)) $cart = ps_cart::initCart(); if( ENABLE_DOWNLOADS == '1') { $not_downloadable = false; require_once( CLASSPATH .'ps_product.php'); for($i = 0; $i < $cart["idx"]; $i++) { if( !ps_product::is_downloadable($cart[$i]['product_id']) ) { $not_downloadable = true; break; } } return !$not_downloadable; } return false; } function noShippingMethodNecessary() { global $cart, $only_downloadable_products; if( NO_SHIPPING == '1') { return true; } if( !isset( $cart)) $cart = ps_cart::initCart(); if( ENABLE_DOWNLOADS == '1') { $not_downloadable = false; require_once( CLASSPATH .'ps_product.php'); for($i = 0; $i < $cart["idx"]; $i++) { if( !ps_product::is_downloadable($cart[$i]['product_id']) ) { $not_downloadable = true; break; } } return !$not_downloadable; } return false; } function noShippingNecessary() { return $this->noShipToNecessary() && $this->noShippingMethodNecessary(); } /** * Retrieve an array with all order steps and their details * * @return array */ function get_checkout_steps() { global $VM_CHECKOUT_MODULES; $stepnames = array_keys( $VM_CHECKOUT_MODULES ); $steps = array(); $i = 0; $last_order = 0; foreach( $VM_CHECKOUT_MODULES as $step ) { // Get the stepname from the array key $stepname = current($stepnames); next($stepnames); switch( $stepname ) { case 'CHECK_OUT_GET_SHIPPING_ADDR': if( ps_checkout::noShipToNecessary() ) $step['enabled'] = 0; break; case 'CHECK_OUT_GET_SHIPPING_METHOD': if( ps_checkout::noShippingMethodNecessary() ) $step['enabled'] = 0; break; } if( $step['enabled'] == 1 ) { $steps[$step['order']][] = $stepname; } } ksort( $steps ); return $steps; } /** * Retrieve the key name of the current checkout step * * @return string */ function get_current_stage() { $steps = ps_checkout::get_checkout_steps(); $stage = key( $steps ); // $steps is sorted by key, so the first key is the first stage // First check the REQUEST parameters for other steps if( !empty( $_REQUEST['checkout_last_step'] ) && empty( $_POST['checkout_this_step'] )) { // Make sure we have an integer (max 4) $checkout_step = abs( min( $_REQUEST['checkout_last_step'], 4 ) ); if( isset( $steps[$checkout_step] )) { return $checkout_step; // it's a valid step } } $checkout_step = (int)vmGet( $_REQUEST, 'checkout_stage' ); if( isset( $steps[$checkout_step] )) { return $checkout_step; // it's a valid step } // Else: we have no alternative steps given by REQUEST while ($step = current($steps)) { if( !empty($_POST['checkout_this_step']) ) { foreach( $step as $stepname ) { if( in_array( $stepname, $_POST['checkout_this_step'])) { next($steps); $key = key( $steps ); if( empty( $key )) { // We are beyond the last index of the array and need to go "back" to the last index end( $steps ); } //echo "Stage: ".key( $steps ); return key($steps); } } } next($steps); } return $stage; } /** * Displays the "checkout bar" using the checkout bar template * * @param array $steps_to_do Array holding all steps the customer has to make * @param array $step_msg Array containing the step messages * @param int $step_count Number of steps to make * @param int $highlighted_step The index of the recent step */ function show_checkout_bar() { global $sess, $ship_to_info_id, $shipping_rate_id, $VM_LANG; if (SHOW_CHECKOUT_BAR != '1' || defined('VM_CHECKOUT_BAR_LOADED')) { return; } // Let's assemble the steps $steps = ps_checkout::get_checkout_steps(); $step_count = sizeof( $steps ); $steps_tmp = $steps; $i = 0; foreach( $steps as $step ) { foreach( $step as $step_name ) { switch ( $step_name ) { case 'CHECK_OUT_GET_SHIPPING_ADDR': $step_msg = $VM_LANG->_('PHPSHOP_ADD_SHIPTO_2'); break; case 'CHECK_OUT_GET_SHIPPING_METHOD': $step_msg = $VM_LANG->_('PHPSHOP_ISSHIP_LIST_CARRIER_LBL'); break; case 'CHECK_OUT_GET_PAYMENT_METHOD': $step_msg = $VM_LANG->_('PHPSHOP_ORDER_PRINT_PAYMENT_LBL'); break; case 'CHECK_OUT_GET_FINAL_CONFIRMATION': $step_msg = $VM_LANG->_('PHPSHOP_CHECKOUT_CONF_PAYINFO_COMPORDER'); break; } $steps_to_do[$i][] = array('step_name' => $step_name, 'step_msg' => $step_msg, 'step_order' => key($steps_tmp) ); } next( $steps_tmp ); $i++; } $highlighted_step = ps_checkout::get_current_stage(); $theme = new $GLOBALS['VM_THEMECLASS'](); $theme->set_vars( array( 'step_count' => $step_count, 'steps_to_do' => $steps_to_do, 'steps' => $steps, 'highlighted_step' => $highlighted_step, 'ship_to_info_id' => vmGet($_REQUEST, 'ship_to_info_id'), 'shipping_rate_id' => vmGet( $_REQUEST, 'shipping_rate_id') ) ); echo $theme->fetch( 'checkout/checkout_bar.tpl.php'); define('VM_CHECKOUT_BAR_LOADED', 1 ); } /** * Called to validate the form values before the order is stored * * @author gday * @author soeren * * @param array $d * @return boolean */ function validate_form(&$d) { global $VM_LANG, $PSHOP_SHIPPING_MODULES, $vmLogger; $db = new ps_DB; $auth = $_SESSION['auth']; $cart = $_SESSION['cart']; if (!$cart["idx"]) { $q = "SELECT order_id FROM #__{vm}_orders WHERE user_id='" . $auth["user_id"] . "' "; $q .= "ORDER BY cdate DESC"; $db->query($q); $db->next_record(); $d["order_id"] = $db->f("order_id"); return False; } if( PSHOP_AGREE_TO_TOS_ONORDER == '1' ) { if( empty( $d["agreed"] )) { $vmLogger->warning( $VM_LANG->_('PHPSHOP_AGREE_TO_TOS',false) ); return false; } } if ( !ps_checkout::noShippingMethodNecessary() ) { if ( !$this->validate_shipping_method($d) ) { return False; } } if ( !$this->validate_payment_method( $d, false )) { return false; } if( CHECK_STOCK == '1' ) { for($i = 0; $i < $cart["idx"]; $i++) { $quantity_in_stock = ps_product::get_field($cart[$i]["product_id"], 'product_in_stock'); $product_name = ps_product::get_field($cart[$i]["product_id"], 'product_name'); if( $cart[$i]["quantity"] > $quantity_in_stock ) { $vmLogger->err( 'The Quantity for the Product "'.$product_name.'" in your Cart ('.$cart[$i]["quantity"].') exceeds the Quantity in Stock ('.$quantity_in_stock.'). We are very sorry for this Inconvenience, but you you need to lower the Quantity in Cart for this Product.'); return false; } } } // calculate the unix timestamp for the specified expiration date // default the day to the 1st $expire_timestamp = @mktime(0,0,0,$_SESSION["ccdata"]["order_payment_expire_month"], 15,$_SESSION["ccdata"]["order_payment_expire_year"]); $_SESSION["ccdata"]["order_payment_expire"] = $expire_timestamp; return True; } /** * Validates the variables prior to adding an order * * @param array $d * @return boolean */ function validate_add(&$d) { global $auth, $VM_LANG, $vmLogger; require_once(CLASSPATH.'ps_payment_method.php'); $ps_payment_method = new ps_payment_method; if( empty( $auth['user_id'] ) ) { $vmLogger->err('Sorry, but it is not possible to order without a User ID. Please contact the Store Administrator if this Error occurs again.'); return false; } if (!ps_checkout::noShipToNecessary()) { if (empty($d["ship_to_info_id"])) { $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_SHIPTO',false) ); return False; } } /* if (!$d["payment_method_id"]) { $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_MSG_4',false) ); return False; }*/ if ($ps_payment_method->is_creditcard(@$d["payment_method_id"])) { if (empty($_SESSION["ccdata"]["order_payment_number"])) { $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_CCNR',false) ); return False; } if(!$ps_payment_method->validate_payment($d["payment_method_id"], $_SESSION["ccdata"]["order_payment_number"])) { $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_CCNUM_INV',false) ); return False; } if(empty( $_SESSION["ccdata"]["order_payment_expire"])) { $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_CCDATE_INV',false) ); return False; } } return True; } function validate_shipto(&$d) { //TODO to be implemented } /** * Called to validate the shipping_method * * @param array $d * @return boolean */ function validate_shipping_method(&$d) { global $VM_LANG, $PSHOP_SHIPPING_MODULES, $vmLogger; if( empty($d['shipping_rate_id']) ) { $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_SHIP',false) ); return false; } if( is_callable( array($this->_SHIPPING, 'validate') )) { if(!$this->_SHIPPING->validate( $d )) { $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_OTHER_SHIP',false) ); return false; } } return true; } /** * Called to validate the payment_method * If payment with CreditCard is used, than the Data must be in stored in the session * This has be done to prevent sending the CreditCard Number back in hidden fields * If the parameter $is_test is true the Number Visa Creditcard number 4111 1111 1111 1111 * * @param array $d * @param boolean $is_test * @return boolean */ function validate_payment_method(&$d, $is_test) { global $VM_LANG, $vmLogger, $order_total; $auth = $_SESSION['auth']; $cart = $_SESSION['cart']; // We don't need to validate a payment method when // the user has no order total he should pay if( empty( $_REQUEST['order_total'])) { if( isset( $d['order_total'])) { if( round( $d['order_total'], 2 ) <= 0.00 ) { return true; } } if( isset($order_total) && $order_total <= 0.00 ) { return true; } } if (!isset($d["payment_method_id"]) || $d["payment_method_id"]==0 ) { $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_PAYM',false) ); return false; } require_once(CLASSPATH.'ps_payment_method.php'); $ps_payment_method = new ps_payment_method; $dbp = new ps_DB; //DB Payment_method // Now Check if all needed Payment Information are entered // Bank Information is found in the User_Info $w = "SELECT `enable_processor` FROM `#__{vm}_payment_method` WHERE "; $w .= "payment_method_id=" . (int)$d["payment_method_id"]; $dbp->query($w); $dbp->next_record(); if (($dbp->f("enable_processor") == "Y") || ($dbp->f("enable_processor") == "")) { // Creditcard if (empty( $_SESSION['ccdata']['creditcard_code']) ) { $vmLogger->err( $VM_LANG->_('VM_CHECKOUT_ERR_CCTYPE') ); return false; } // $_SESSION['ccdata'] = $ccdata; // The Data should be in the session if (!isset($_SESSION['ccdata'])) { //Not? Then Error $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_CCDATA',false) ); return False; } if (!$_SESSION['ccdata']['order_payment_number']) { $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_CCNR_FOUND',false) ); return False; } // CREDIT CARD NUMBER CHECK // USING THE CREDIT CARD CLASS in ps_payment if(!$ps_payment_method->validate_payment( $_SESSION['ccdata']['creditcard_code'], $_SESSION['ccdata']['order_payment_number'])) { $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_CCDATE',false) ); return False; } if (!$is_test) { $payment_number = ereg_replace(" |-", "", $_SESSION['ccdata']['order_payment_number']); if ($payment_number == "4111111111111111") { $vmLogger->warning( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_TEST',false) ); return False; } } if(!empty($_SESSION['ccdata']['need_card_code']) && empty($_SESSION['ccdata']['credit_card_code'])) { $vmLogger->err( $VM_LANG->_('PHPSHOP_CUSTOMER_CVV2_ERROR',false) ); return False; } if(!$_SESSION['ccdata']['order_payment_expire_month']) { $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_CCMON',false) ); return False; } if(!$_SESSION['ccdata']['order_payment_expire_year']) { $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_CCYEAR',false) ); return False; } $date = getdate( time() ); if ($_SESSION['ccdata']['order_payment_expire_year'] < $date["year"] or ($_SESSION['ccdata']['order_payment_expire_year'] == $date["year"] and $_SESSION['ccdata']['order_payment_expire_month'] < $date["mon"])) { $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_CCDATE_INV',false) ); return False; } return True; } elseif ($dbp->f("enable_processor") == "B") { $_SESSION['ccdata']['creditcard_code'] = ""; $_SESSION['ccdata']['order_payment_name'] = ""; $_SESSION['ccdata']['order_payment_number'] = ""; $_SESSION['ccdata']['order_payment_expire_month'] = ""; $_SESSION['ccdata']['order_payment_expire_year'] = ""; // Bank Account require_once( CLASSPATH . 'ps_user.php' ); $dbu =& ps_user::getUserInfo( $auth["user_id"], array( 'bank_account_holder','bank_iban','bank_account_nr','bank_sort_code','bank_name' ) ); if ( $dbu->f("bank_account_holder") == "" || $dbu->f("bank_account_nr") =="" ) { if( !empty($d['bank_account_holder']) && !empty($d['bank_account_nr'])) { // Insert the given data $fields = array( 'bank_account_holder' => $d['bank_account_holder'], 'bank_account_nr' => $d['bank_account_nr'], 'bank_sort_code' => $d['bank_sort_code'], 'bank_name' => $d['bank_name'], 'bank_iban' => $d['bank_iban'] ); ps_user::setUserInfo( $fields, $auth["user_id"] ); $dbu =& ps_user::getUserInfo( $auth["user_id"], array( 'bank_account_holder','bank_iban','bank_account_nr','bank_sort_code','bank_name' ) ); } else { $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_USER_DATA',false) ); return False; } } if ($dbu->f("bank_account_holder") == ""){ $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_BA_HOLDER_NAME',false) ); return False; } if (($dbu->f("bank_iban") == "") and ($dbu->f("bank_account_nr") =="")) { $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_IBAN',false) ); return False; } if ($dbu->f("bank_iban") == "") { if ($dbu->f("bank_account_nr") == ""){ $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_BA_NUM',false) ); return False; } if ($dbu->f("bank_sort_code") == ""){ $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_BANK_SORT',false) ); return False; } if ($dbu->f("bank_name") == ""){ $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_BANK_NAME',false) ); return False; } } } else { $_SESSION['ccdata']['creditcard_code'] = ''; $_SESSION['ccdata']['order_payment_name'] = ""; $_SESSION['ccdata']['order_payment_number'] = ""; $_SESSION['ccdata']['order_payment_expire_month'] = ""; $_SESSION['ccdata']['order_payment_expire_year'] = ""; } // Enter additional Payment check procedures here if neccessary return True; } /** * Update order details * CURRENTLY UNUSED * * @param array $d * @return boolean */ function update(&$d) { global $vmLogger; $db = new ps_DB; $timestamp = time(); if ($this->validate_update($d)) { return True; } else { $vmLogger->err( $this->error ); return False; } } /** * Control Function for the Checkout Process * @author Ekkhard Domning * @author soeren * @param array $d * @return boolean */ function process(&$d) { global $checkout_this_step, $sess,$VM_LANG, $vmLogger; $ccdata = array(); if( empty($d["checkout_this_step"]) || !is_array(@$d["checkout_this_step"])) { $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_VALID_STEP',false) ); return false; } foreach($d["checkout_this_step"] as $checkout_this_step) { switch($checkout_this_step) { case 'CHECK_OUT_GET_FINAL_BASKET' : break; case 'CHECK_OUT_GET_SHIPPING_ADDR' : // The User has choosen a Shipping address if (empty($d["ship_to_info_id"])) { $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_SHIPTO',false) ); unset( $_POST['checkout_this_step']); return False; } break; case 'CHECK_OUT_GET_SHIPPING_METHOD': // The User has choosen a Shipping method if (!$this->validate_shipping_method($d)) { unset( $_POST['checkout_this_step']); return false; } break; case 'CHECK_OUT_GET_PAYMENT_METHOD': // The User has choosen a payment method $_SESSION['ccdata']['order_payment_name'] = @$d['order_payment_name']; // VISA, AMEX, DISCOVER.... $_SESSION['ccdata']['creditcard_code'] = @$d['creditcard_code']; $_SESSION['ccdata']['order_payment_number'] = @$d['order_payment_number']; $_SESSION['ccdata']['order_payment_expire_month'] = @$d['order_payment_expire_month']; $_SESSION['ccdata']['order_payment_expire_year'] = @$d['order_payment_expire_year']; // 3-digit Security Code (CVV) $_SESSION['ccdata']['credit_card_code'] = @$d['credit_card_code']; if (!$this->validate_payment_method($d, false)) { //Change false to true to Let the user play with the VISA Testnumber unset( $_POST['checkout_this_step']); return false; } break; case 'CHECK_OUT_GET_FINAL_CONFIRMATION': // The User wants to order now, validate everything, if OK than Add immeditialtly return( $this->add( $d ) ); default: $vmLogger->crit( "CheckOut step ($checkout_this_step) is undefined!" ); return false; } // end switch } return true; } // end function process /** * Prints the List of all shipping addresses of a user * * @param unknown_type $user_id * @param unknown_type $name * @param unknown_type $value */ function ship_to_addresses_radio($user_id, $name, $value) { echo ps_checkout::list_addresses( $user_id, $name, $value ); } /** * Creates a Radio List of all shipping addresses of a user * * @param int $user_id * @param string $name * @param string $value */ function list_addresses( $user_id, $name, $value ) { global $sess,$VM_LANG; $db = new ps_DB; /* Select all the ship to information for this user id and * order by modification date; most recently changed to oldest */ $q = "SELECT * from #__{vm}_user_info WHERE "; $q .= "user_id=" . (int)$user_id . ' '; $q .= "AND address_type='BT'"; $db->query($q); $db->next_record(); $bt_user_info_id = $db->f("user_info_id"); $q = "SELECT * FROM #__{vm}_user_info i "; $q .= "INNER JOIN #__{vm}_country c ON (i.country=c.country_3_code) "; $q .= "LEFT JOIN #__{vm}_state s ON (i.state=s.state_2_code AND s.country_id=c.country_id) "; $q .= "WHERE user_id =" . (int)$user_id . ' '; $q .= "AND address_type = 'ST' "; $q .= "ORDER by address_type_name, mdate DESC"; $db->query($q); $theme = vmTemplate::getInstance(); $theme->set_vars(array('db' => $db, 'user_id' => $user_id, 'name' => $name, 'value' => $value, 'bt_user_info_id' => $bt_user_info_id, ) ); echo $theme->fetch( 'checkout/list_shipto_addresses.tpl.php'); } /** * Fetches the address information for the currently logged in user * * @param string $address_type Can be BT (Bill To) or ST (Shipto address) */ function display_address($address_type='BT') { $auth = $_SESSION['auth']; $address_type = $address_type == 'BT' ? $address_type : 'ST'; $db = new ps_DB; $q = "SELECT * FROM #__{vm}_user_info i "; $q .= "INNER JOIN #__{vm}_country c ON (i.country=c.country_3_code OR i.country=c.country_2_code) "; $q .= "LEFT JOIN #__{vm}_state s ON (i.state=s.state_2_code AND s.country_id=c.country_id) "; $q .= "WHERE user_id='" . $auth["user_id"] . "' "; $q .= "AND address_type='BT'"; $db->query($q); $db->next_record(); $theme = new $GLOBALS['VM_THEMECLASS'](); $theme->set('db', $db ); return $theme->fetch('checkout/customer_info.tpl.php'); } /** * Lists Shipping Methods of all published Shipping Modules * * @param string $ship_to_info_id * @param string $shipping_method_id */ function list_shipping_methods( $ship_to_info_id=null, $shipping_method_id=null ) { global $PSHOP_SHIPPING_MODULES, $vmLogger, $auth, $weight_total; if( empty( $ship_to_info_id )) { // Get the Bill to user_info_id $database = new ps_DB(); $database->setQuery( "SELECT user_info_id FROM #__{vm}_user_info WHERE user_id=".$auth['user_id']." AND address_type='BT'" ); $vars["ship_to_info_id"] = $_REQUEST['ship_to_info_id'] = $database->loadResult(); } else { $vars['ship_to_info_id'] = $ship_to_info_id; } $vars['shipping_rate_id'] = $shipping_method_id; $vars["weight"] = $weight_total; $vars['zone_qty'] = vmRequest::getInt( 'zone_qty', 0 ); $i = 0; $theme = new $GLOBALS['VM_THEMECLASS'](); $theme->set_vars(array('vars' => $vars, 'PSHOP_SHIPPING_MODULES' => $PSHOP_SHIPPING_MODULES ) ); echo $theme->fetch( 'checkout/list_shipping_methods.tpl.php'); } /** * Lists the payment methods of all available payment modules * @static * @param int $payment_method_id */ function list_payment_methods( $payment_method_id=0 ) { global $order_total, $sess, $VM_CHECKOUT_MODULES; $ps_vendor_id = $_SESSION['ps_vendor_id']; $auth = $_SESSION['auth']; $ship_to_info_id = vmGet( $_REQUEST, 'ship_to_info_id' ); $shipping_rate_id = vmGet( $_REQUEST, 'shipping_rate_id' ); require_once(CLASSPATH . 'ps_payment_method.php'); $ps_payment_method = new ps_payment_method; require_once( CLASSPATH. 'ps_creditcard.php' ); $ps_creditcard = new ps_creditcard(); $count = 0; // Do we have Credit Card Payments? $db_cc = new ps_DB; $q = "SELECT * from #__{vm}_payment_method,#__{vm}_shopper_group WHERE "; $q .= "#__{vm}_payment_method.shopper_group_id=#__{vm}_shopper_group.shopper_group_id "; $q .= "AND (#__{vm}_payment_method.shopper_group_id='".$auth['shopper_group_id']."' "; $q .= "OR #__{vm}_shopper_group.default='1') "; $q .= "AND (enable_processor='' OR enable_processor='Y') "; $q .= "AND payment_enabled='Y' "; $q .= "AND #__{vm}_payment_method.vendor_id='$ps_vendor_id' "; $q .= " ORDER BY list_order"; $db_cc->query($q); if ($db_cc->num_rows()) { $first_payment_method_id = $db_cc->f("payment_method_id"); $count += $db_cc->num_rows(); $cc_payments=true; } else { $cc_payments=false; } $db_nocc = new ps_DB; $q = "SELECT * from #__{vm}_payment_method,#__{vm}_shopper_group WHERE "; $q .= "#__{vm}_payment_method.shopper_group_id=#__{vm}_shopper_group.shopper_group_id "; $q .= "AND (#__{vm}_payment_method.shopper_group_id='".$auth['shopper_group_id']."' "; $q .= "OR #__{vm}_shopper_group.default='1') "; $q .= "AND (enable_processor='B' OR enable_processor='N' OR enable_processor='P') "; $q .= "AND payment_enabled='Y' "; $q .= "AND #__{vm}_payment_method.vendor_id='$ps_vendor_id' "; $q .= " ORDER BY list_order"; $db_nocc->query($q); if ($db_nocc->next_record()) { $nocc_payments=true; $first_payment_method_id = $db_nocc->f("payment_method_id"); $count += $db_nocc->num_rows(); $db_nocc->reset(); } else { $nocc_payments=false; } // Redirect to the last step when there's only one payment method if( $VM_CHECKOUT_MODULES['CHECK_OUT_GET_PAYMENT_METHOD']['order'] != $VM_CHECKOUT_MODULES['CHECK_OUT_GET_FINAL_CONFIRMATION']['order'] ) { if ($count <= 1 && $cc_payments==false) { vmRedirect($sess->url(SECUREURL.basename($_SERVER['PHP_SELF'])."?page=checkout.index&payment_method_id=$first_payment_method_id&ship_to_info_id=$ship_to_info_id&shipping_rate_id=".urlencode($shipping_rate_id)."&checkout_stage=".$VM_CHECKOUT_MODULES['CHECK_OUT_GET_FINAL_CONFIRMATION']['order'], false, false ),""); } elseif( isset($order_total) && $order_total <= 0.00 ) { // In case the order total is less than or equal zero, we don't need a payment method vmRedirect($sess->url(SECUREURL.basename($_SERVER['PHP_SELF'])."?page=checkout.index&ship_to_info_id=$ship_to_info_id&shipping_rate_id=".urlencode($shipping_rate_id)."&checkout_stage=".$VM_CHECKOUT_MODULES['CHECK_OUT_GET_FINAL_CONFIRMATION']['order'], false, false),""); } } $theme = new $GLOBALS['VM_THEMECLASS'](); $theme->set_vars(array('db_nocc' => $db_nocc, 'db_cc' => $db_cc, 'nocc_payments' => $nocc_payments, 'payment_method_id' => $payment_method_id, 'first_payment_method_id' => $first_payment_method_id, 'count' => $count, 'cc_payments' => $cc_payments, 'ps_creditcard' => $ps_creditcard, 'ps_payment_method' => $ps_payment_method ) ); echo $theme->fetch( 'checkout/list_payment_methods.tpl.php'); } /** * This is the main function which stores the order information in the database * * @author gday, soeren, many others! * @param array $d The REQUEST/$vars array * @return boolean */ function add( &$d ) { global $order_tax_details, $afid, $VM_LANG, $auth, $my, $mosConfig_offset, $vmLogger, $vmInputFilter, $discount_factor; $ps_vendor_id = $_SESSION["ps_vendor_id"]; $cart = $_SESSION['cart']; require_once(CLASSPATH. 'ps_payment_method.php' ); $ps_payment_method = new ps_payment_method; require_once(CLASSPATH. 'ps_product.php' ); $ps_product= new ps_product; require_once(CLASSPATH.'ps_cart.php'); $ps_cart = new ps_cart; $db = new ps_DB; /* Set the order number */ $order_number = $this->get_order_number(); $totals = $this->calc_order_totals( $d ); extract( $totals ); //$timestamp = time() + ($mosConfig_offset*60*60); //Original $timestamp = time(); //Custom if (!$this->validate_form($d)) { return false; } if (!$this->validate_add($d)) { return false; } // make sure Total doesn't become negative if( $order_total < 0 ) $order_total = 0; $order_total = round( $order_total, 2); $vmLogger->debug( '-- Checkout Debug-- Subtotal: '.$order_subtotal.' Taxable: '.$order_taxable.' Payment Discount: '.$payment_discount.' Coupon Discount: '.$coupon_discount.' Shipping: '.$order_shipping.' Shipping Tax : '.$order_shipping_tax.' Tax : '.$order_tax.' ------------------------ Order Total: '.$order_total.' ----------------------------' ); // Check to see if Payment Class File exists $payment_class = $ps_payment_method->get_field($d["payment_method_id"], "payment_class"); $enable_processor = $ps_payment_method->get_field($d["payment_method_id"], "enable_processor"); if (file_exists(CLASSPATH . "payment/$payment_class.php") ) { if( !class_exists( $payment_class )) { include( CLASSPATH. "payment/$payment_class.php" ); } $_PAYMENT = new $payment_class(); if (!$_PAYMENT->process_payment($order_number,$order_total, $d)) { $vmLogger->err( $VM_LANG->_('PHPSHOP_PAYMENT_ERROR',false)." ($payment_class)" ); $_SESSION['last_page'] = "checkout.index"; $_REQUEST["checkout_next_step"] = CHECK_OUT_GET_PAYMENT_METHOD; return False; } } else { $d["order_payment_log"] = $VM_LANG->_('PHPSHOP_CHECKOUT_MSG_LOG'); } // Remove the Coupon, because it is a Gift Coupon and now is used!! if( @$_SESSION['coupon_type'] == "gift" ) { $d['coupon_id'] = $_SESSION['coupon_id']; include_once( CLASSPATH.'ps_coupon.php' ); ps_coupon::remove_coupon_code( $d ); } // Get the IP Address if (!empty($_SERVER['REMOTE_ADDR'])) { $ip = $_SERVER['REMOTE_ADDR']; } else { $ip = 'unknown'; } // Collect all fields and values to store them! $fields = array( 'user_id' => $auth["user_id"], 'vendor_id' => $ps_vendor_id, 'order_number' => $order_number, 'user_info_id' => $d["ship_to_info_id"], 'ship_method_id' => @urldecode($d["shipping_rate_id"]), 'order_total' => $order_total, 'order_subtotal' => $order_subtotal, 'order_tax' => $order_tax, 'order_tax_details' => serialize($order_tax_details), 'order_shipping' => $order_shipping, 'order_shipping_tax' => $order_shipping_tax, 'order_discount' => $payment_discount, 'coupon_discount' => $coupon_discount, 'coupon_code' => @$_SESSION['coupon_code'], 'order_currency' => $GLOBALS['product_currency'], 'order_status' => 'P', 'cdate' => $timestamp, 'mdate' => $timestamp, 'customer_note' => htmlspecialchars(vmRequest::getString('customer_note','', 'POST', 'none' ), ENT_QUOTES ), 'ip_address' => $ip ); // Insert the main order information $db->buildQuery( 'INSERT', '#__{vm}_orders', $fields ); $result = $db->query(); $d["order_id"] = $order_id = $db->last_insert_id(); if( $result === false || empty( $order_id )) { $vmLogger->crit( 'Adding the Order into the Database failed! User ID: '.$auth["user_id"] ); return false; } // Insert the initial Order History. $mysqlDatetime = date("Y-m-d G:i:s", $timestamp); $fields = array( 'order_id' => $order_id, 'order_status_code' => 'P', 'date_added' => $mysqlDatetime, 'customer_notified' => 1, 'comments' => '' ); $db->buildQuery( 'INSERT', '#__{vm}_order_history', $fields ); $db->query(); /** * Insert the Order payment info */ $payment_number = ereg_replace(" |-", "", @$_SESSION['ccdata']['order_payment_number']); $d["order_payment_code"] = @$_SESSION['ccdata']['credit_card_code']; // Payment number is encrypted using mySQL encryption functions. $fields = array( 'order_id' => $order_id, 'payment_method_id' => $d["payment_method_id"], 'order_payment_log' => @$d["order_payment_log"], 'order_payment_trans_id' => $vmInputFilter->safeSQL( @$d["order_payment_trans_id"] ) ); if( !empty( $payment_number ) && VM_STORE_CREDITCARD_DATA == '1' ) { // Store Credit Card Information only if the Store Owner has decided to do so $fields['order_payment_code'] = $d["order_payment_code"]; $fields['order_payment_expire'] = @$_SESSION["ccdata"]["order_payment_expire"]; $fields['order_payment_name'] = @$_SESSION["ccdata"]["order_payment_name"]; $fields['order_payment_number'] = VM_ENCRYPT_FUNCTION."( '$payment_number','" . ENCODE_KEY . "')"; $specialfield = array('order_payment_number'); } else { $specialfield = array(); } $db->buildQuery( 'INSERT', '#__{vm}_order_payment', $fields, '', $specialfield ); $db->query(); /** * Insert the User Billto & Shipto Info */ // First: get all the fields from the user field list to copy them from user_info into the order_user_info $fields = array(); require_once( CLASSPATH . 'ps_userfield.php' ); $userfields = ps_userfield::getUserFields('', false, '', true, true ); foreach ( $userfields as $field ) { if ($field->name=='email') $fields[] = 'user_email'; else $fields[] = $field->name; } $fieldstr = implode( ',', $fields ); // Save current Bill To Address $q = "INSERT INTO `#__{vm}_order_user_info` (`order_info_id`,`order_id`,`user_id`,address_type, ".$fieldstr.") "; $q .= "SELECT NULL, '$order_id', '".$auth['user_id']."', address_type, ".$fieldstr." FROM #__{vm}_user_info WHERE user_id='".$auth['user_id']."' AND address_type='BT'"; $db->query( $q ); // Save current Ship to Address if applicable $q = "INSERT INTO `#__{vm}_order_user_info` (`order_info_id`,`order_id`,`user_id`,address_type, ".$fieldstr.") "; $q .= "SELECT NULL, '$order_id', '".$auth['user_id']."', address_type, ".$fieldstr." FROM #__{vm}_user_info WHERE user_id='".$auth['user_id']."' AND user_info_id='".$d['ship_to_info_id']."' AND address_type='ST'"; $db->query( $q ); /** * Insert all Products from the Cart into order line items; * one row per product in the cart */ $dboi = new ps_DB; for($i = 0; $i < $cart["idx"]; $i++) { $r = "SELECT product_id,product_in_stock,product_sales,product_parent_id,product_sku,product_name "; $r .= "FROM #__{vm}_product WHERE product_id='".$cart[$i]["product_id"]."'"; $dboi->query($r); $dboi->next_record(); $product_price_arr = $ps_product->get_adjusted_attribute_price($cart[$i]["product_id"], $cart[$i]["description"]); $product_price = $GLOBALS['CURRENCY']->convert( $product_price_arr["product_price"], $product_price_arr["product_currency"] ); if( empty( $_SESSION['product_sess'][$cart[$i]["product_id"]]['tax_rate'] )) { $my_taxrate = $ps_product->get_product_taxrate($cart[$i]["product_id"] ); } else { $my_taxrate = $_SESSION['product_sess'][$cart[$i]["product_id"]]['tax_rate']; } // Attribute handling $product_parent_id = $dboi->f('product_parent_id'); $description = ''; if( $product_parent_id > 0 ) { $db_atts = $ps_product->attribute_sql( $dboi->f('product_id'), $product_parent_id ); while( $db_atts->next_record()) { $description .= $db_atts->f('attribute_name').': '.$db_atts->f('attribute_value').'; '; } } $description .= $ps_product->getDescriptionWithTax($_SESSION['cart'][$i]["description"], $dboi->f('product_id')); $product_final_price = round( ($product_price *($my_taxrate+1)), 2 ); $vendor_id = $ps_vendor_id; $fields = array('order_id' => $order_id, 'user_info_id' => $d["ship_to_info_id"], 'vendor_id' => $vendor_id, 'product_id' => $cart[$i]["product_id"], 'order_item_sku' => $dboi->f("product_sku"), 'order_item_name' => $dboi->f("product_name"), 'product_quantity' => $cart[$i]["quantity"], 'product_item_price' => $product_price, 'product_final_price' => $product_final_price, 'order_item_currency' => $GLOBALS['product_currency'], 'order_status' => 'P', 'product_attribute' => $description, 'cdate' => $timestamp, 'mdate' => $timestamp ); $db->buildQuery( 'INSERT', '#__{vm}_order_item', $fields ); $db->query(); // Update Stock Level and Product Sales, decrease - no matter if in stock or not! $q = "UPDATE #__{vm}_product "; $q .= "SET product_in_stock = product_in_stock - ".(int)$cart[$i]["quantity"]; $q .= " WHERE product_id = '" . $cart[$i]["product_id"]. "'"; $db->query($q); $q = "UPDATE #__{vm}_product "; $q .= "SET product_sales= product_sales + ".(int)$cart[$i]["quantity"]; $q .= " WHERE product_id='".$cart[$i]["product_id"]."'"; $db->query($q); } ######## BEGIN DOWNLOAD MOD ############### if( ENABLE_DOWNLOADS == "1" ) { ######## BEGIN JOOMDLE MOD ############### require_once(JPATH_ADMINISTRATOR.DS.'components'.DS.'com_joomdle'.DS.'helpers'.DS.'content.php'); /* Get product type ID for Courses */ $query = "SELECT product_type_id from #__vm_product_type where product_type_name='Course'"; $db->setQuery($query); $items = $db->loadObjectList(); if ($db->getErrorNum()) { JError::raiseWarning( 500, $db->stderr() ); } $type_id = $items[0]->product_type_id; ######## END JOOMDLE MOD ############### require_once( CLASSPATH.'ps_order.php'); for($i = 0; $i < $cart["idx"]; $i++) { ######## BEGIN JOOMDLE MOD ############### $product_id = $cart[$i]["product_id"]; $query = "SELECT product_id from #__vm_product_type_$type_id where product_id='$product_id'"; $db->setQuery($query); $p_ids = $db->loadObjectList(); if ($db->getErrorNum()) { JError::raiseWarning( 500, $db->stderr() ); } /* If it is a course don't treat it as a download */ if (count ($p_ids)) continue; ######## END JOOMDLE MOD ############### // only handle downloadable products here if( ps_product::is_downloadable($cart[$i]["product_id"])) { $params = array('product_id' => $cart[$i]["product_id"], 'order_id' => $order_id, 'user_id' => $auth["user_id"] ); ps_order::insert_downloads_for_product( $params ); if( @VM_DOWNLOADABLE_PRODUCTS_KEEP_STOCKLEVEL == '1' ) { // Update the product stock level back to where it was. $q = "UPDATE #__{vm}_product "; $q .= "SET product_in_stock = product_in_stock + ".(int)$cart[$i]["quantity"]; $q .= " WHERE product_id = '" .(int)$cart[$i]["product_id"]. "'"; $db->query($q); } } } ######## BEGIN JOOMDLE MOD ############### //if ($payment_class == 'ps_authorize') // In case you want only some payment methods //{ // For each item ir order, check if it is a course // In that case, process all courses in order and break for($i = 0; $i < $cart["idx"]; $i++) { $product_id = $cart[$i]["product_id"]; $query = "SELECT product_id from #__vm_product_type_$type_id where product_id='$product_id'"; $db->setQuery($query); $p_ids = $db->loadObjectList(); if ($db->getErrorNum()) { JError::raiseWarning( 500, $db->stderr() ); } /* If it is a course */ if (count ($p_ids)) { $user_id = $db->f("user_id"); /* add_order_enrols enrols the user and set order status to 'C' but, ahead, VM changes it to P again as configured when notifying customer */ JoomdleHelperContent::add_order_enrols ($order_id, $user_id); break; } } //} ######## END JOOMDLE MOD ############### } ################## END DOWNLOAD MOD ########### // Export the order_id so the checkout complete page can get it $d["order_id"] = $order_id; /* * Let the shipping module know which shipping method * was selected. This way it can save any information * it might need later to print a shipping label. */ if( is_callable( array($this->_SHIPPING, 'save_rate_info') )) { $this->_SHIPPING->save_rate_info($d); } // Now as everything else has been done, we can update // the Order Status if the Payment Method is // "Use Payment Processor", because: // Payment Processors return false on any error // Only completed payments return true! $update_order = false; if( $enable_processor == "Y" ) { if( defined($_PAYMENT->payment_code.'_VERIFIED_STATUS')) { $d['order_status'] = constant($_PAYMENT->payment_code.'_VERIFIED_STATUS'); $update_order = true; } } elseif( $order_total == 0.00 ) { // If the Order Total is zero, we can confirm the order to automatically enable the download $d['order_status'] = ENABLE_DOWNLOAD_STATUS; $update_order = true; } if ( $update_order ) { require_once(CLASSPATH."ps_order.php"); $ps_order = new ps_order(); $ps_order->order_status_update($d); } // Send the e-mail confirmation messages $this->email_receipt($order_id); // Reset the cart (=empty it) $ps_cart->reset(); $_SESSION['savedcart']['idx']=0; $ps_cart->saveCart(); // Unset the payment_method variables $d["payment_method_id"] = ""; $d["order_payment_number"] = ""; $d["order_payment_expire"] = ""; $d["order_payment_name"] = ""; $d["credit_card_code"] = ""; // Clear the sensitive Session data $_SESSION['ccdata']['order_payment_name'] = ""; $_SESSION['ccdata']['order_payment_number'] = ""; $_SESSION['ccdata']['order_payment_expire_month'] = ""; $_SESSION['ccdata']['order_payment_expire_year'] = ""; $_SESSION['ccdata']['credit_card_code'] = ""; $_SESSION['coupon_discount'] = ""; $_SESSION['coupon_id'] = ""; $_SESSION['coupon_redeemed'] = false; $_POST["payment_method_id"] = ""; $_POST["order_payment_number"] = ""; $_POST["order_payment_expire"] = ""; $_POST["order_payment_name"] = ""; /* if( empty($my->id) && !empty( $auth['user_id'])) { require_once(CLASSPATH.'ps_user.php'); ps_user::logout(); } */ return True; } /** * Create an order number using the session id, session * name, and the current unix timestamp. * * @return string */ function get_order_number() { global $auth; /* Generated a unique order number */ $str = session_id(); $str .= (string)time(); $order_number = $auth['user_id'] .'_'. md5($str); return substr($order_number, 0, 32); } /** * Stores the md5 hash of the recent cart in the var _cartHash * */ function generate_cart_hash() { $this->_cartHash = $this->get_new_cart_hash(); } function get_order_total( &$d ) { global $discount_factor; $totals = $this->calc_order_totals($d); return $totals['order_total']; } /** * Calculates the current order totals and fills an array with all the values * * @param array $d * @return array */ function calc_order_totals( &$d ) { global $discount_factor, $mosConfig_offset; $totals = array(); /* sets _subtotal */ $totals['order_subtotal'] = $tmp_subtotal = $this->calc_order_subtotal($d); $totals['order_taxable'] = $this->calc_order_taxable($d); if( !empty($d['payment_method_id'])) { $totals['payment_discount'] = $d['payment_discount'] = $this->get_payment_discount($d['payment_method_id'], $totals['order_subtotal']); } else { $totals['payment_discount'] = $d['payment_discount'] = 0.00; } /* DISCOUNT HANDLING */ if( !empty($_SESSION['coupon_discount']) ) { $totals['coupon_discount'] = floatval($_SESSION['coupon_discount']); } else { $totals['coupon_discount'] = 0.00; } // make sure Total doesn't become negative if( $tmp_subtotal < 0 ) $totals['order_subtotal'] = $tmp_subtotal = 0; if( $totals['order_taxable'] < 0 ) $totals['order_taxable'] = 0; // from now on we have $order_tax_details $d['order_tax'] = $totals['order_tax'] = round( $this->calc_order_tax($totals['order_taxable'], $d), 2 ); if( is_object($this->_SHIPPING) ) { /* sets _shipping */ $d['order_shipping'] = $totals['order_shipping'] = round( $this->calc_order_shipping( $d ), 2 ); /* sets _shipping_tax * btw: This is WEIRD! To get an exactly rounded value we have to convert * the amount to a String and call "round" with the string. */ $d['order_shipping_tax'] = $totals['order_shipping_tax'] = round( strval($this->calc_order_shipping_tax($d)), 2 ); } else { $d['order_shipping'] = $totals['order_shipping'] = $totals['order_shipping_tax'] = $d['order_shipping_tax'] = 0.00; } $d['order_total'] = $totals['order_total'] = $tmp_subtotal + $totals['order_tax'] + $totals['order_shipping'] + $totals['order_shipping_tax'] - $totals['coupon_discount'] - $totals['payment_discount']; $totals['order_tax'] *= $discount_factor; return $totals; } /** * Generates the md5 hash of the recent cart / checkout constellation * * @return unknown */ function get_new_cart_hash() { return md5( print_r( $_SESSION['cart'], true) . vmGet($_REQUEST,'shipping_rate_id') . vmGet($_REQUEST,'payment_method_id') ); } /** * Returns the recent subtotal * * @param array $d * @return float The current order subtotal */ function get_order_subtotal( &$d ) { if( $this->_subtotal === null ) { $this->_subtotal = $this->calc_order_subtotal( $d ); } else { if( $this->_cartHash != $this->get_new_cart_hash() ) { // Need to re-calculate the subtotal $this->_subtotal = $this->calc_order_subtotal( $d ); } } return $this->_subtotal; } /************************************************************************** ** name: calc_order_subtotal() ** created by: gday ** description: Calculate the order subtotal for the current order. ** Does not include tax or shipping charges. ** parameters: $d ** returns: sub total for this order ***************************************************************************/ function calc_order_subtotal( &$d ) { global $order_tax_details; $order_tax_details = array(); $d['order_subtotal_withtax'] = 0; $d['payment_discount'] = 0; $auth = $_SESSION['auth']; $cart = $_SESSION['cart']; $order_subtotal = 0; require_once(CLASSPATH.'ps_product.php'); $ps_product= new ps_product; for($i = 0; $i < $cart["idx"]; $i++) { $my_taxrate = $ps_product->get_product_taxrate($cart[$i]["product_id"] ); $price = $ps_product->get_adjusted_attribute_price($cart[$i]["product_id"], $cart[$i]["description"]); $product_price = $product_price_tmp = $GLOBALS['CURRENCY']->convert( $price["product_price"], @$price["product_currency"] ); if( $auth["show_price_including_tax"] == 1 ) { $product_price = round( ($product_price *($my_taxrate+1)), 2 ); $product_price *= $cart[$i]["quantity"]; $d['order_subtotal_withtax'] += $product_price; $product_price = $product_price /($my_taxrate+1); $order_subtotal += $product_price; } else { $order_subtotal += $product_price * $cart[$i]["quantity"]; $product_price = round( ($product_price *($my_taxrate+1)), 2 ); $product_price *= $cart[$i]["quantity"]; $d['order_subtotal_withtax'] += $product_price; $product_price = $product_price /($my_taxrate+1); } if( MULTIPLE_TAXRATES_ENABLE ) { // Calculate the amounts for each tax rate if( !isset( $order_tax_details[$my_taxrate] )) { $order_tax_details[$my_taxrate] = 0; } $order_tax_details[$my_taxrate] += $product_price_tmp*$my_taxrate*$cart[$i]["quantity"]; } } return($order_subtotal); } /** * Calculates the taxable order subtotal for the order. * If an item has no weight, it is non taxable. * @author Chris Coleman * @param array $d * @return float Subtotal */ function calc_order_taxable($d) { $auth = $_SESSION['auth']; $cart = $_SESSION['cart']; $subtotal = 0.0; require_once(CLASSPATH.'ps_product.php'); $ps_product= new ps_product; require_once(CLASSPATH.'ps_shipping_method.php'); $db = new ps_DB; for($i = 0; $i < $cart["idx"]; $i++) { $price = $ps_product->get_adjusted_attribute_price($cart[$i]["product_id"], $cart[$i]["description"]); $product_price = $GLOBALS['CURRENCY']->convert( $price["product_price"], $price['product_currency'] ); $item_weight = ps_shipping_method::get_weight($cart[$i]["product_id"]) * $cart[$i]['quantity']; if ($item_weight != 0 or TAX_VIRTUAL=='1') { $subtotal += $product_price * $cart[$i]["quantity"]; } } return($subtotal); } /** * Calculate the tax charges for the current order. * You can switch the way, taxes are calculated: * either based on the VENDOR address, * or based on the ship-to address. * ! Creates the global $order_tax_details * * @param float $order_taxable * @param array $d * @return float */ function calc_order_tax($order_taxable, $d) { global $order_tax_details, $discount_factor; $total = 0; $order_tax=0; $auth = $_SESSION['auth']; $ps_vendor_id = $_SESSION["ps_vendor_id"]; $db = new ps_DB; $ship_to_info_id = vmGet( $_REQUEST, 'ship_to_info_id'); require_once(CLASSPATH.'ps_tax.php'); $ps_tax = new ps_tax; $discount_factor = 1; // Shipping address based TAX if ( !ps_checkout::tax_based_on_vendor_address () ) { $q = "SELECT state, country FROM #__{vm}_user_info "; $q .= "WHERE user_info_id='".$ship_to_info_id. "'"; $db->query($q); $db->next_record(); $state = $db->f("state"); $country = $db->f("country"); $q = "SELECT * FROM #__{vm}_tax_rate WHERE tax_country='$country' "; if( !empty($state)) { $q .= "AND (tax_state='$state' OR tax_state=' $state ')"; } $db->query($q); if ($db->next_record()) { $rate = $order_taxable * floatval( $db->f("tax_rate") ); if (empty($rate)) { $order_tax = 0.0; } else { $cart = $_SESSION['cart']; $order_tax = 0.0; if( (!empty( $_SESSION['coupon_discount'] ) || !empty( $d['payment_discount'] )) && PAYMENT_DISCOUNT_BEFORE == '1' ) { require_once(CLASSPATH.'ps_product.php'); $ps_product= new ps_product; for($i = 0; $i < $cart["idx"]; $i++) { $item_weight = ps_shipping_method::get_weight($cart[$i]["product_id"]) * $cart[$i]['quantity']; if ($item_weight !=0 or TAX_VIRTUAL) { $price = $ps_product->get_adjusted_attribute_price($cart[$i]["product_id"], $cart[$i]["description"]); $price['product_price'] = $GLOBALS['CURRENCY']->convert( $price['product_price'], $price['product_currency']); $tax_rate = $db->f("tax_rate"); $use_coupon_discount= @$_SESSION['coupon_discount']; //if( !empty( $_SESSION['coupon_discount'] )) { // if( $auth["show_price_including_tax"] == 1 ) { // $use_coupon_discount = $_SESSION['coupon_discount'] / ($tax_rate+1); // } //} $factor = (100 * ($use_coupon_discount + @$d['payment_discount'])) / $this->_subtotal; $price["product_price"] = $price["product_price"] - ($factor * $price["product_price"] / 100); @$order_tax_details[$tax_rate] += $price["product_price"] * $tax_rate * $cart[$i]["quantity"]; $order_tax += $price["product_price"] * $tax_rate * $cart[$i]["quantity"]; $total += $price["product_price"] * $cart[$i]["quantity"]; } else { $order_tax += 0.0; } } } else { $order_tax = $rate; } } } else { $order_tax = 0.0; } $order_tax_details[$db->f('tax_rate')] = $order_tax; } // Store Owner Address based TAX else { // Calculate the Tax with a tax rate for every product $cart = $_SESSION['cart']; $order_tax = 0.0; $total = 0.0; if( (!empty( $_SESSION['coupon_discount'] ) || !empty( $d['payment_discount'] )) && PAYMENT_DISCOUNT_BEFORE == '1' ) { // We need to recalculate the tax details when the discounts are applied // BEFORE taxes - because they affect the product subtotals then $order_tax_details = array(); } require_once(CLASSPATH.'ps_product.php'); $ps_product= new ps_product; require_once(CLASSPATH.'ps_shipping_method.php'); for($i = 0; $i < $cart["idx"]; $i++) { $item_weight = ps_shipping_method::get_weight($cart[$i]["product_id"]) * $cart[$i]['quantity']; if ($item_weight !=0 or TAX_VIRTUAL) { $price = $ps_product->get_adjusted_attribute_price($cart[$i]["product_id"], $cart[$i]["description"]); $price['product_price'] = $GLOBALS['CURRENCY']->convert( $price['product_price'], $price['product_currency']); $tax_rate = $ps_product->get_product_taxrate($cart[$i]["product_id"]); if( (!empty( $_SESSION['coupon_discount'] ) || !empty( $d['payment_discount'] )) && PAYMENT_DISCOUNT_BEFORE == '1' ) { $use_coupon_discount= @$_SESSION['coupon_discount']; if( !empty( $_SESSION['coupon_discount'] )) { if( $auth["show_price_including_tax"] == 1 ) { $use_coupon_discount = $_SESSION['coupon_discount'] / ($tax_rate+1); } } $factor = (100 * ($use_coupon_discount + @$d['payment_discount'])) / $this->_subtotal; $price["product_price"] = $price["product_price"] - ($factor * $price["product_price"] / 100); @$order_tax_details[$tax_rate] += $price["product_price"] * $tax_rate * $cart[$i]["quantity"]; } $order_tax += $price["product_price"] * $tax_rate * $cart[$i]["quantity"]; $total += $price["product_price"] * $cart[$i]["quantity"]; } } if( (!empty( $_SESSION['coupon_discount'] ) || !empty( $d['payment_discount'] )) && PAYMENT_DISCOUNT_BEFORE != '1' ) { // Here we need to re-calculate the Discount // because we assume the Discount is "including Tax" $discounted_total = @$d['order_subtotal_withtax'] - @$_SESSION['coupon_discount'] - @$d['payment_discount']; if( $discounted_total != @$d['order_subtotal_withtax'] && @$d['order_subtotal_withtax'] > 0.00) { $discount_factor = $discounted_total / $d['order_subtotal_withtax']; foreach( $order_tax_details as $rate => $value ) { $order_tax_details[$rate] = $value * $discount_factor; } } } if( is_object($this->_SHIPPING) ) { $taxrate = $this->_SHIPPING->get_tax_rate(); if( $taxrate ) { $rate = $this->_SHIPPING->get_rate( $d ); if( $auth["show_price_including_tax"] == 1 ) { @$order_tax_details[$taxrate] += $rate - ($rate / ($taxrate+1)); } else { @$order_tax_details[$taxrate] += $rate * $taxrate; } } } } return( round( $order_tax, 2 ) ); } /************************************************************************** ** name: calc_order_shipping() ** created by: soeren ** description: Get the Shipping costs WITHOUT TAX ** parameters: $d, ** returns: a decimal number, excluding taxes ***************************************************************************/ function calc_order_shipping( &$d ) { $auth = $_SESSION['auth']; $shipping_total = $this->_SHIPPING->get_rate( $d ); $shipping_taxrate = $this->_SHIPPING->get_tax_rate(); // When the Shipping rate is shown including Tax // we have to extract the Tax from the Shipping Total // before returning the value if( $auth["show_price_including_tax"] == 1 ) { $d['shipping_tax'] = $shipping_total - ($shipping_total / ($shipping_taxrate+1)); $d['shipping_total'] = $shipping_total - $d['shipping_tax']; } else { $d['shipping_tax'] = $shipping_total * $shipping_taxrate; $d['shipping_total'] = $shipping_total; } $d['shipping_tax'] = $GLOBALS['CURRENCY']->convert( $d['shipping_tax'] ); $d['shipping_total'] = $GLOBALS['CURRENCY']->convert( $d['shipping_total'] ); return $d['shipping_total']; } /************************************************************************** ** name: calc_order_shipping_tax() ** created by: Soeren ** description: Calculate the tax for the shipping of the current order ** Assumes that the function calc_order_shipping has been called before ** parameters: $d ** returns: Tax for the shipping of this order ***************************************************************************/ function calc_order_shipping_tax($d) { return $d['shipping_tax']; } /************************************************************************** ** name: get_vendor_currency() ** created by: gday ** description: Get the currency type used by the $vendor_id ** parameters: $vendor_id - vendor id to return currency type ** returns: Currency type for this vendor ***************************************************************************/ function get_vendor_currency($vendor_id) { $db = new ps_DB; $q = "SELECT vendor_currency FROM #__{vm}_vendor WHERE vendor_id='$vendor_id'"; $db->query($q); $db->next_record(); $currency = $db->f("vendor_currency"); return($currency); } /************************************************************************** ** name: get_payment_discount() ** created by: soeren ** description: Get the discount for the selected payment ** parameters: $payment_method_id ** returns: Discount as a decimal if found ** 0 if nothing is found ***************************************************************************/ function get_payment_discount( $payment_method_id, $subtotal = '' ) { if( empty( $payment_method_id )) { return 0; } $db = new ps_DB(); //MOD ei // There is a special payment method, which fee is depend on subtotal // it is a type of cash on delivery // comment soeren: Payment methods can implement their own method // how to calculate the discount: the function "get_payment_rate" // should return a float value from the payment class require_once(CLASSPATH.'ps_payment_method.php'); $ps_payment_method = new ps_payment_method; $payment_class = $ps_payment_method->get_field($payment_method_id, "payment_class"); // Check to see if Payment Class File exists if (file_exists(CLASSPATH . "payment/$payment_class.php") ) { require_once( CLASSPATH. "payment/$payment_class.php" ); eval( "\$_PAYMENT = new $payment_class();" ); if(is_callable(array($payment_class, 'get_payment_rate'))) { return $_PAYMENT->get_payment_rate($subtotal); } } //End of MOD ei // If a payment method has no special way of calculating a discount, // let's do this on our own from the payment_method_discount settings $q = 'SELECT `payment_method_discount`,`payment_method_discount_is_percent`,`payment_method_discount_max_amount`, `payment_method_discount_min_amount` FROM `#__{vm}_payment_method` WHERE payment_method_id='.$payment_method_id; $db->query($q);$db->next_record(); $discount = $db->f('payment_method_discount'); $is_percent = $db->f('payment_method_discount_is_percent'); if( !$is_percent ) { // Standard method: absolute amount if (!empty($discount)) { return(floatval( $GLOBALS['CURRENCY']->convert($discount))); } else { return(0); } } else { if( $subtotal === '') { $subtotal = $this->get_order_subtotal( $vars ); } // New: percentage of the subtotal, limited by minimum and maximum $max = $db->f('payment_method_discount_max_amount'); $min = $db->f('payment_method_discount_min_amount'); $value = (float) ($discount/100) * $subtotal; if( abs($value) > $max && $max > 0 ) { $value = -$max; } elseif( abs($value) < $min && $min > 0 ) { $value = -$min; } return $value; } } /** * Create a receipt for the current order and email it to * the customer and the vendor. * @author gday * @author soeren * @param int $order_id * @return boolean True on success, false on failure */ function email_receipt($order_id) { global $sess, $ps_product, $VM_LANG, $CURRENCY_DISPLAY, $vmLogger, $mosConfig_fromname, $mosConfig_lang, $database; $ps_vendor_id = vmGet( $_SESSION, 'ps_vendor_id', 1 ); $auth = $_SESSION["auth"]; require_once( CLASSPATH.'ps_order_status.php'); require_once( CLASSPATH.'ps_userfield.php'); require_once(CLASSPATH.'ps_product.php'); $ps_product = new ps_product; // Connect to database and gather appropriate order information $db = new ps_DB; $q = "SELECT * FROM #__{vm}_orders WHERE order_id='$order_id'"; $db->query($q); $db->next_record(); $user_id = $db->f("user_id"); $customer_note = $db->f("customer_note"); $order_status = ps_order_status::getOrderStatusName($db->f("order_status") ); $dbbt = new ps_DB; $dbst = new ps_DB; $qt = "SELECT * FROM #__{vm}_user_info WHERE user_id='".$user_id."' AND address_type='BT'"; $dbbt->query($qt); $dbbt->next_record(); $qt = "SELECT * FROM #__{vm}_user_info WHERE user_info_id='". $db->f("user_info_id") . "'"; $dbst->query($qt); $dbst->next_record(); $dbv = new ps_DB; $qt = "SELECT * from #__{vm}_vendor "; /* Need to decide on vendor_id <=> order relationship */ $qt .= "WHERE vendor_id = '".$ps_vendor_id."'"; $dbv->query($qt); $dbv->next_record(); $dboi = new ps_DB; $q_oi = "SELECT * FROM #__{vm}_product, #__{vm}_order_item, #__{vm}_orders "; $q_oi .= "WHERE #__{vm}_product.product_id=#__{vm}_order_item.product_id "; $q_oi .= "AND #__{vm}_order_item.order_id='$order_id' "; $q_oi .= "AND #__{vm}_orders.order_id=#__{vm}_order_item.order_id"; $dboi->query($q_oi); $db_payment = new ps_DB; $q = "SELECT op.payment_method_id, pm.payment_method_name FROM #__{vm}_order_payment as op, #__{vm}_payment_method as pm WHERE order_id='$order_id' AND op.payment_method_id=pm.payment_method_id"; $db_payment->query($q); $db_payment->next_record(); if ($auth["show_price_including_tax"] == 1) { $order_shipping = $db->f("order_shipping"); $order_shipping += $db->f("order_shipping_tax"); $order_shipping_tax = 0; $order_tax = $db->f("order_tax") + $db->f("order_shipping_tax"); } else { $order_shipping = $db->f("order_shipping"); $order_shipping_tax = $db->f("order_shipping_tax"); $order_tax = $db->f("order_tax"); } $order_total = $db->f("order_total"); $order_discount = $db->f("order_discount"); $coupon_discount = $db->f("coupon_discount"); // Email Addresses for shopper and vendor // ************************************** $shopper_email = $dbbt->f("user_email"); $shopper_name = $dbbt->f("first_name")." ".$dbbt->f("last_name"); $from_email = $dbv->f("contact_email"); $shopper_subject = $dbv->f("vendor_name") . " ".$VM_LANG->_('PHPSHOP_ORDER_PRINT_PO_LBL',false)." - " . $db->f("order_id"); $vendor_subject = $dbv->f("vendor_name") . " ".$VM_LANG->_('PHPSHOP_ORDER_PRINT_PO_LBL',false)." - " . $db->f("order_id"); $shopper_order_link = $sess->url( SECUREURL ."index.php?page=account.order_details&order_id=$order_id", true, false ); $vendor_order_link = $sess->url( SECUREURL ."index2.php?page=order.order_print&order_id=$order_id&pshop_mode=admin", true, false ); /** * Prepare the payment information, including Credit Card information when not empty */ $payment_info_details = $db_payment->f("payment_method_name"); if( !empty( $_SESSION['ccdata']['order_payment_name'] ) && !empty($_SESSION['ccdata']['order_payment_number'])) { $payment_info_details .= '
'.$VM_LANG->_('PHPSHOP_CHECKOUT_CONF_PAYINFO_NAMECARD',false).': '.$_SESSION['ccdata']['order_payment_name'].'
'; $payment_info_details .= $VM_LANG->_('PHPSHOP_CHECKOUT_CONF_PAYINFO_CCNUM',false).': '.$this->asterisk_pad($_SESSION['ccdata']['order_payment_number'], 4 ).'
'; $payment_info_details .= $VM_LANG->_('PHPSHOP_CHECKOUT_CONF_PAYINFO_EXDATE',false).': '.$_SESSION['ccdata']['order_payment_expire_month'].' / '.$_SESSION['ccdata']['order_payment_expire_year'].'
'; if( !empty($_SESSION['ccdata']['credit_card_code'])) { $payment_info_details .= 'CVV code: '.$_SESSION['ccdata']['credit_card_code'].'
'; } } // Convert HTML into Text $payment_info_details_text = str_replace( '
', "\n", $payment_info_details ); // Get the Shipping Details $shipping_arr = explode("|", urldecode(vmGet($_REQUEST,"shipping_rate_id")) ); // Headers and Footers // ****************************** // Shopper Header $shopper_header = $VM_LANG->_('PHPSHOP_CHECKOUT_EMAIL_SHOPPER_HEADER1',false)."\n"; $legal_info_title = ''; $legal_info_html = ''; // Get the legal information about the returns/order cancellation policy if( @VM_ONCHECKOUT_SHOW_LEGALINFO == '1' ) { $article = intval(@VM_ONCHECKOUT_LEGALINFO_LINK); if( $article > 0 ) { $db_legal = new ps_DB(); // Get the content article, which contains the Legal Info $db_legal->query( 'SELECT id, title, introtext FROM #__content WHERE id='.$article ); $db_legal->next_record(); if( $db_legal->f('introtext') ) { $legal_info_title = $db_legal->f('title'); $legal_info_text = strip_tags( str_replace( '
', "\n", $db_legal->f('introtext') )); $legal_info_html = $db_legal->f('introtext'); } } } //Shopper Footer $shopper_footer = "\n\n".$VM_LANG->_('PHPSHOP_CHECKOUT_EMAIL_SHOPPER_HEADER2',false)."\n"; if( VM_REGISTRATION_TYPE != 'NO_REGISTRATION' ) { $shopper_footer .= "\n\n".$VM_LANG->_('PHPSHOP_CHECKOUT_EMAIL_SHOPPER_HEADER5',false)."\n"; $shopper_footer .= $shopper_order_link; } $shopper_footer .= "\n\n".$VM_LANG->_('PHPSHOP_CHECKOUT_EMAIL_SHOPPER_HEADER3',false)."\n"; $shopper_footer .= "Email: " . $from_email; // New in version 1.0.5 if( @VM_ONCHECKOUT_SHOW_LEGALINFO == '1' && !empty( $legal_info_title )) { $shopper_footer .= "\n\n____________________________________________\n"; $shopper_footer .= $legal_info_title."\n"; $shopper_footer .= $legal_info_text."\n"; } // Vendor Header $vendor_header = $VM_LANG->_('PHPSHOP_CHECKOUT_EMAIL_SHOPPER_HEADER4',false)."\n"; // Vendor Footer $vendor_footer = "\n\n".$VM_LANG->_('PHPSHOP_CHECKOUT_EMAIL_SHOPPER_HEADER5',false)."\n"; $vendor_footer .= $vendor_order_link; $vendor_email = $from_email; ///////////////////////////////////// // set up text mail // // Main Email Message Purchase Order // ********************************* $shopper_message = "\n".$VM_LANG->_('PHPSHOP_ORDER_PRINT_PO_LBL',false)."\n"; $shopper_message .= "------------------------------------------------------------------------\n"; $shopper_message .= $VM_LANG->_('PHPSHOP_ORDER_PRINT_PO_NUMBER',false).": " . $db->f("order_id") . "\n"; $shopper_message .= $VM_LANG->_('PHPSHOP_ORDER_PRINT_PO_DATE',false).": "; $shopper_message .= strftime( $VM_LANG->_('DATE_FORMAT_LC'), $db->f("cdate") ) . "\n"; $shopper_message .= $VM_LANG->_('PHPSHOP_ORDER_PRINT_PO_STATUS',false).": "; $shopper_message .= $order_status."\n\n"; // BillTo Fields $registrationfields = ps_userfield::getUserFields('registration', false, '', false, true ); foreach( $registrationfields as $field ) { if( $field->name == 'email') $field->name = 'user_email'; if( $field->name == 'delimiter_sendregistration' || $field->type == 'captcha') continue; if( $field->type == 'delimiter') { $shopper_message .= ($VM_LANG->_($field->title) != '' ? $VM_LANG->_($field->title) : $field->title)."\n"; $shopper_message .= "--------------------\n\n"; } else { $shopper_message .= ($VM_LANG->_($field->title) != '' ? $VM_LANG->_($field->title) : $field->title).': '; $shopper_message .= $dbbt->f($field->name) . "\n"; } } // Shipping Fields $shopper_message .= "\n\n"; $shopper_message .= $VM_LANG->_('PHPSHOP_ORDER_PRINT_SHIP_TO_LBL')."\n"; $shopper_message .= "-------\n\n"; $shippingfields = ps_userfield::getUserFields('shipping', false, '', false, true ); foreach( $shippingfields as $field ) { if( $field->type == 'delimiter') { $shopper_message .= ($VM_LANG->_($field->title) != '' ? $VM_LANG->_($field->title) : $field->title)."\n"; $shopper_message .= "--------------------\n\n"; } else { $shopper_message .= ($VM_LANG->_($field->title) != '' ? $VM_LANG->_($field->title) : $field->title).': '; $shopper_message .= $dbst->f($field->name) . "\n"; } } $shopper_message .= "\n\n"; $shopper_message .= $VM_LANG->_('PHPSHOP_ORDER_PRINT_ITEMS_LBL',false)."\n"; $shopper_message .= "-----------"; $sub_total = 0.00; while($dboi->next_record()) { $shopper_message .= "\n\n"; $shopper_message .= $VM_LANG->_('PHPSHOP_PRODUCT',false)." = "; if ($dboi->f("product_parent_id")) { $shopper_message .= $dboi->f("order_item_name") . "\n"; $shopper_message .= "SERVICE = "; } $shopper_message .= $dboi->f("product_name") . "; ".$dboi->f("product_attribute") ."\n"; $shopper_message .= $VM_LANG->_('PHPSHOP_ORDER_PRINT_QUANTITY',false)." = "; $shopper_message .= $dboi->f("product_quantity") . "\n"; $shopper_message .= $VM_LANG->_('PHPSHOP_ORDER_PRINT_SKU',false)." = "; $shopper_message .= $dboi->f("order_item_sku") . "\n"; $shopper_message .= $VM_LANG->_('PHPSHOP_ORDER_PRINT_PRICE',false)." = "; if ($auth["show_price_including_tax"] == 1) { $sub_total += ($dboi->f("product_quantity") * $dboi->f("product_final_price")); $shopper_message .= $CURRENCY_DISPLAY->getFullValue($dboi->f("product_final_price"), '', $db->f('order_currency')); } else { $sub_total += ($dboi->f("product_quantity") * $dboi->f("product_final_price")); $shopper_message .= $CURRENCY_DISPLAY->getFullValue($dboi->f("product_item_price"), '', $db->f('order_currency')); } } $shopper_message .= "\n\n"; $shopper_message .= $VM_LANG->_('PHPSHOP_ORDER_PRINT_SUBTOTAL',false)." = "; $shopper_message .= $CURRENCY_DISPLAY->getFullValue($sub_total, '', $db->f('order_currency'))."\n"; if ( PAYMENT_DISCOUNT_BEFORE == '1') { if( !empty($order_discount)) { if ($order_discount > 0) { $shopper_message .= $VM_LANG->_('PHPSHOP_PAYMENT_METHOD_LIST_DISCOUNT',false)." = "; $shopper_message .= "- ".$CURRENCY_DISPLAY->getFullValue(abs($order_discount), '', $db->f('order_currency')) . "\n"; } else { $shopper_message .= $VM_LANG->_('PHPSHOP_FEE',false)." = "; $shopper_message .= "+ ".$CURRENCY_DISPLAY->getFullValue(abs($order_discount), '', $db->f('order_currency')) . "\n"; } } if( !empty($coupon_discount)) { /* following 2 lines added by Erich for coupon hack */ $shopper_message .= $VM_LANG->_('PHPSHOP_COUPON_DISCOUNT',false) . ": "; $shopper_message .= $CURRENCY_DISPLAY->getFullValue($coupon_discount, '', $db->f('order_currency')) . "\n"; } } if ($auth["show_price_including_tax"] != 1) { $shopper_message .= $VM_LANG->_('PHPSHOP_ORDER_PRINT_TOTAL_TAX',false)." = "; $shopper_message .= $CURRENCY_DISPLAY->getFullValue($order_tax, '', $db->f('order_currency')) . "\n"; } $shopper_message .= $VM_LANG->_('PHPSHOP_ORDER_PRINT_SHIPPING',false)." = "; $shopper_message .= $CURRENCY_DISPLAY->getFullValue($order_shipping, '', $db->f('order_currency')) . "\n"; if( !empty($order_shipping_tax)) { $shopper_message .= $VM_LANG->_('PHPSHOP_ORDER_PRINT_SHIPPING_TAX',false)." = "; $shopper_message .= $CURRENCY_DISPLAY->getFullValue($order_shipping_tax, '', $db->f('order_currency')); } $shopper_message .= "\n\n"; if ( PAYMENT_DISCOUNT_BEFORE != '1') { if( !empty($order_discount)) { if ($order_discount > 0) { $shopper_message .= $VM_LANG->_('PHPSHOP_PAYMENT_METHOD_LIST_DISCOUNT',false)." = "; $shopper_message .= "- ".$CURRENCY_DISPLAY->getFullValue(abs($order_discount), '', $db->f('order_currency')) . "\n"; } else { $shopper_message .= $VM_LANG->_('PHPSHOP_FEE',false)." = "; $shopper_message .= "+ ".$CURRENCY_DISPLAY->getFullValue(abs($order_discount), '', $db->f('order_currency')) . "\n"; } } if( !empty($coupon_discount)) { /* following 2 lines added by Erich for coupon hack */ $shopper_message .= $VM_LANG->_('PHPSHOP_COUPON_DISCOUNT',false) . ": "; $shopper_message .= $CURRENCY_DISPLAY->getFullValue($coupon_discount, '', $db->f('order_currency')) . "\n"; } } $shopper_message .= $VM_LANG->_('PHPSHOP_ORDER_PRINT_TOTAL',false)." = "; $shopper_message .= $CURRENCY_DISPLAY->getFullValue($order_total, '', $db->f('order_currency')); if ($auth["show_price_including_tax"] == 1) { $shopper_message .= "\n---------------"; $shopper_message .= "\n"; $shopper_message .= $VM_LANG->_('PHPSHOP_ORDER_PRINT_TOTAL_TAX',false)." = "; $shopper_message .= $CURRENCY_DISPLAY->getFullValue($order_tax, '', $db->f('order_currency')) . "\n"; } if( $db->f('order_tax_details') ) { $shopper_message .= str_replace( '
', "\n", ps_checkout::show_tax_details( $db->f('order_tax_details'), $db->f('order_currency') )); } // Payment Details $shopper_message .= "\n\n------------------------------------------------------------------------\n"; $shopper_message .= $payment_info_details_text; // Shipping Details if( is_object($this->_SHIPPING) ) { $shopper_message .= "\n\n------------------------------------------------------------------------\n"; $shopper_message .= $VM_LANG->_('PHPSHOP_ORDER_PRINT_SHIPPING_LBL',false).":\n"; $shopper_message .= $shipping_arr[1]." (".$shipping_arr[2].")"; } // Customer Note $shopper_message .= "\n\n------------------------------------------------------------------------\n"; $shopper_message .= "\n".$VM_LANG->_('PHPSHOP_ORDER_PRINT_CUSTOMER_NOTE',false)."\n"; $shopper_message .= "---------------"; $shopper_message .= "\n"; if( !empty( $customer_note )) { $shopper_message .= $customer_note."\n"; } else { $shopper_message .= " ./. \n"; } $shopper_message .= "------------------------------------------------------------------------\n"; // Decode things like € => € $shopper_message = vmHtmlEntityDecode( $shopper_message ); // End of Purchase Order // ********************* // //END: set up text mail ///////////////////////////////////// // Send text email // if (ORDER_MAIL_HTML == '0') { $msg = $shopper_header . $shopper_message . $shopper_footer; // Mail receipt to the shopper vmMail( $from_email, $mosConfig_fromname, $shopper_email, $shopper_subject, $msg, "" ); $msg = $vendor_header . $shopper_message . $vendor_footer; // Mail receipt to the vendor vmMail($from_email, $mosConfig_fromname, $vendor_email, $vendor_subject, $msg, "" ); } //////////////////////////// // set up the HTML email // elseif (ORDER_MAIL_HTML == '1') { $dboi->query($q_oi); // Create Template Object $template = vmTemplate::getInstance(); if ($order_discount > 0) { $order_discount_lbl = $VM_LANG->_('PHPSHOP_PAYMENT_METHOD_LIST_DISCOUNT'); $order_discount_plusminus = '-'; } else { $order_discount_lbl = $VM_LANG->_('PHPSHOP_FEE'); $order_discount_plusminus = '+'; } if ($coupon_discount > 0) { $coupon_discount_lbl = $VM_LANG->_('PHPSHOP_PAYMENT_METHOD_LIST_DISCOUNT'); $coupon_discount_plusminus = '-'; } else { $coupon_discount_lbl = $VM_LANG->_('PHPSHOP_FEE'); $coupon_discount_plusminus = '+'; } if( is_object($this->_SHIPPING) ) { $shipping_info_details = stripslashes($shipping_arr[1])." (".stripslashes($shipping_arr[2]).")"; } else { $shipping_info_details = ' ./. '; } // These are a lot of vars to import for the email confirmation $template->set_vars(array( 'is_email_to_shopper' => true, 'db' => $db, 'dboi' => $dboi, 'dbbt' => $dbbt, 'dbst' => $dbst, 'ps_product' => $ps_product, 'shippingfields' => $shippingfields, 'registrationfields' => $registrationfields, 'order_id' => $order_id, 'order_discount' => $order_discount, 'order_discount_lbl' => $order_discount_lbl, 'order_discount_plusminus' => $order_discount_plusminus, 'coupon_discount' => $coupon_discount, 'coupon_discount_lbl' => $coupon_discount_lbl, 'coupon_discount_plusminus' => $coupon_discount_plusminus, 'order_date' => $VM_LANG->convert( vmFormatDate($db->f("cdate"), $VM_LANG->_('DATE_FORMAT_LC') )), 'order_status' => $order_status, 'legal_info_title' => $legal_info_title, 'legal_info_html' => $legal_info_html, 'order_link' => $shopper_order_link, 'payment_info_lbl' => $VM_LANG->_('PHPSHOP_ORDER_PRINT_PAYINFO_LBL'), 'payment_info_details' => $payment_info_details, 'shipping_info_lbl' => $VM_LANG->_('PHPSHOP_ORDER_PRINT_SHIPPING_LBL'), 'shipping_info_details' => $shipping_info_details, 'from_email' => $from_email, 'customer_note' => nl2br($customer_note), 'order_header_msg' => $shopper_header, 'order_subtotal' => $CURRENCY_DISPLAY->getFullValue($sub_total, '', $db->f('order_currency')), 'order_shipping' => $CURRENCY_DISPLAY->getFullValue($order_shipping, '', $db->f('order_currency')), 'order_tax' => $CURRENCY_DISPLAY->getFullValue($order_tax, '', $db->f('order_currency')). ps_checkout::show_tax_details( $db->f('order_tax_details'), $db->f('order_currency') ), 'order_total' => $CURRENCY_DISPLAY->getFullValue($order_total, '', $db->f('order_currency')), )); $shopper_html = $template->fetch('order_emails/confirmation_email.tpl.php'); // Reset the list of order items for use in the vendor email $dboi->reset(); // Override some vars for the vendor email, so we can use the same template $template->set_vars(array( 'order_header_msg' => $vendor_header, 'order_link' => $vendor_order_link, 'is_email_to_shopper' => false )); $vendor_html = $template->fetch('order_emails/confirmation_email.tpl.php'); /* * Add the text, html and embedded images. * The name of the image should match exactly * (case-sensitive) to the name in the html. */ $shopper_mail_Body = $shopper_html; $shopper_mail_AltBody = $shopper_header . $shopper_message . $shopper_footer; $vendor_mail_Body = $vendor_html; $vendor_mail_AltBody = $vendor_header . $shopper_message . $vendor_footer; $imagefile = pathinfo($dbv->f("vendor_full_image")); $extension = $imagefile['extension'] == "jpg" ? "jpeg" : "jpeg"; $EmbeddedImages[] = array( 'path' => IMAGEPATH."vendor/".$dbv->f("vendor_full_image"), 'name' => "vendor_image", 'filename' => $dbv->f("vendor_full_image"), 'encoding' => "base64", 'mimetype' => "image/".$extension ); $shopper_mail = vmMail( $from_email, $mosConfig_fromname, $shopper_email, $shopper_subject, $shopper_mail_Body, $shopper_mail_AltBody, true, null, null, $EmbeddedImages); $vendor_mail = vmMail( $from_email, $mosConfig_fromname, $vendor_email, $vendor_subject, $vendor_mail_Body, $vendor_mail_AltBody, true, null, null, $EmbeddedImages, null, $shopper_email); if ( !$shopper_mail || !$vendor_mail ) { $vmLogger->debug( 'Something went wrong while sending the order confirmation email to '.$from_email.' and '.$shopper_email ); return false; } // // END: set up and send the HTML email //////////////////////////////////////// } return true; } // end of function email_receipt() /** * Return $str with all but $display_length at the end as asterisks. * @author gday * * @param string $str The string to mask * @param int $display_length The length at the end of the string that is NOT masked * @param boolean $reversed When true, masks the end. Masks from the beginning at default * @return string The string masked by asteriks */ function asterisk_pad($str, $display_length, $reversed = false) { $total_length = strlen($str); if($total_length > $display_length) { if( !$reversed) { for($i = 0; $i < $total_length - $display_length; $i++) { $str[$i] = "*"; } } else { for($i = $total_length-1; $i >= $total_length - $display_length; $i--) { $str[$i] = "*"; } } } return($str); } /** * Displays the order_tax_details array when it contains * more than one * @param mixed $details * @return string */ function show_tax_details( $details, $currency = '' ) { global $discount_factor, $CURRENCY_DISPLAY, $VM_LANG; if( !isset( $discount_factor) || !empty($_REQUEST['discount_factor'])) { $discount_factor = 1; } $auth = $_SESSION['auth']; if( !is_array( $details )) { $details = @unserialize( $details ); if( !is_array($details)) { return false; } } $html_rate = ''; $html = ''; if( sizeof( $details) > 1 ) { foreach ($details as $rate => $value ) { if( !$auth['show_price_including_tax']) { $value /= $discount_factor; } if ( !empty($value) ){ $rate = str_replace( '-', $CURRENCY_DISPLAY->decimal, $rate )*100; $html_rate .= $CURRENCY_DISPLAY->getFullValue( $value, 5, $currency ).' ('.$rate.'% '.$VM_LANG->_('PHPSHOP_CART_TAX').')
'; } } if ( !empty( $html_rate )){ $html = '
'.$VM_LANG->_('VM_TAXDETAILS_LABEL').':
'.$html_rate ; } } return $html; } /* * @abstract This function is very useful to round totals with definite decimals. * * @param float $value * @param integer $dec * @return float */ function approx( $value, $dec = 2 ) { $value += 0.0; $unit = floor( $value * pow( 10, $dec + 1 ) ) / 10; $round = round( $unit ); return $round / pow( 10, $dec ); } /** * If the customer is in the EU then tax should be charged according to the * vendor's address, and this function will return true. */ function tax_based_on_vendor_address ($ship_to_info_id = '') { global $__tax_based_on_vendor_address; global $vmLogger; if (!isset ($__tax_based_on_vendor_address)) { $__tax_based_on_vendor_address = ps_checkout::_tax_based_on_vendor_address ($ship_to_info_id); if ($__tax_based_on_vendor_address) $vmLogger->debug ('calculating tax based on vendor address'); else $vmLogger->debug ('calculating tax based on shipping address'); } return $__tax_based_on_vendor_address; } function _tax_based_on_vendor_address ($ship_to_info_id = '') { global $auth; global $vmLogger; switch (TAX_MODE) { case '0': return false; case '1': return true; case '17749': $ship_to_info_id = !empty($ship_to_info_id)? $ship_to_info_id : vmGet( $_REQUEST, 'ship_to_info_id'); $db = new ps_DB; $q = "SELECT country FROM #__{vm}_user_info WHERE user_info_id='" . $ship_to_info_id ."'"; $db->query($q); $db->next_record(); $ship_country = $db->f("country"); if (! array_key_exists ('country', $auth) || empty( $ship_country ) ) { $vmLogger->debug ('shopper\'s country is not known; defaulting to vendor-based tax'); return true; } if ( $ship_to_info_id ) { $vmLogger->debug ('shopper shipping in ' . $ship_country); $auth_country = $ship_country; } else { $vmLogger->debug ('shopper is in ' . $auth['country']); $auth_country = $auth['country']; } return ps_checkout::country_in_eu_common_vat_zone ( $auth_country ); default: $vmLogger->warning ('unknown TAX_MODE "' . TAX_MODE . '"'); return true; } } function country_in_eu_common_vat_zone ($country) { $eu_countries = array ('AUT', 'BGR', 'BEL', 'CYP', 'CZE', 'DEU', 'DNK', 'ESP', 'EST', 'FIN', 'FRA', 'FXX', 'GBR', 'GRC', 'HUN', 'IRL', 'ITA', 'LVA', 'LTU', 'LUX', 'MLT', 'NLD', 'POL', 'PRT', 'ROM', 'SVK', 'SVN', 'SWE'); return in_array ($country, $eu_countries); } } // Check if there is an extended class in the Themes and if it is allowed to use them // If the class is called outside Virtuemart, we have to make sure to load the settings // Thomas Kahl - Feb. 2009 if (!defined('VM_ALLOW_EXTENDED_CLASSES') && file_exists(dirname(__FILE__).'/../virtuemart.cfg.php')) { include_once(dirname(__FILE__).'/../virtuemart.cfg.php'); } // If settings are loaded, extended Classes are allowed and the class exisits... if (defined('VM_ALLOW_EXTENDED_CLASSES') && defined('VM_THEMEPATH') && VM_ALLOW_EXTENDED_CLASSES && file_exists(VM_THEMEPATH.'user_class/'.basename(__FILE__))) { // Load the theme-user_class as extended include_once(VM_THEMEPATH.'user_class/'.basename(__FILE__)); } else { // Otherwise we have to use the original classname to extend the core-class class ps_checkout extends vm_ps_checkout {} } ?>