PageRenderTime 58ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/administrator/components/com_virtuemart/classes/ps_checkout.php

http://vanphongphamdm.googlecode.com/
PHP | 1895 lines | 1262 code | 263 blank | 370 comment | 254 complexity | d7a4ef4d1a956cedfe8c3e5d704e0807 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1, Apache-2.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. if( !defined( '_VALID_MOS' ) && !defined( '_JEXEC' ) ) die( 'Direct Access to '.basename(__FILE__).' is not allowed.' );
  3. /**
  4. *
  5. * @version $Id: ps_checkout.php 1830 2009-06-26 20:52:15Z Aravot $
  6. * @package VirtueMart
  7. * @subpackage classes
  8. * @copyright Copyright (C) 2004-2011 VirtueMart Team - All rights reserved.
  9. * @license http://www.gnu.org/copyleft/gpl.html GNU/GPL, see LICENSE.php
  10. * VirtueMart is free software. This version may have been modified pursuant
  11. * to the GNU General Public License, and as distributed it includes or
  12. * is derivative of works licensed under the GNU General Public License or
  13. * other free or open source software licenses.http://goo.gl/INjCq
  14. * See /administrator/components/com_virtuemart/COPYRIGHT.php for copyright notices and details.
  15. *
  16. * http://virtuemart.net
  17. */
  18. define("CHECK_OUT_GET_FINAL_BASKET", 1);
  19. define("CHECK_OUT_GET_SHIPPING_ADDR", 2);
  20. define("CHECK_OUT_GET_SHIPPING_METHOD", 3);
  21. define("CHECK_OUT_GET_PAYMENT_METHOD", 4);
  22. define("CHECK_OUT_GET_FINAL_CONFIRMATION", 99);
  23. /**
  24. * The class contains the shop checkout code. It is used to checkout
  25. * and order and collect payment information.
  26. *
  27. */
  28. class vm_ps_checkout {
  29. var $_SHIPPING = null;
  30. var $_subtotal = null;
  31. var $_shipping = null;
  32. var $_shipping_tax = null;
  33. var $_payment_discount = null;
  34. var $_coupon_discount = null;
  35. var $_order_total = null;
  36. /** @var string An md5 hash of print_r( $cart, true ) to check wether the checkout values have to be renewed */
  37. var $_cartHash;
  38. /**
  39. * Initiate Shipping Modules
  40. */
  41. function vm_ps_checkout() {
  42. global $vendor_freeshipping, $vars, $PSHOP_SHIPPING_MODULES;
  43. // Make a snapshot of the current checkout configuration
  44. $this->generate_cart_hash();
  45. /* Ok, need to decide if we have a free Shipping amount > 0,
  46. * and IF the cart total is more than that Free Shipping amount,
  47. * let's set Order Shipping = 0
  48. */
  49. $this->_subtotal = $this->get_order_subtotal($vars);
  50. if( $vendor_freeshipping > 0 && $vars['order_subtotal_withtax'] >= $vendor_freeshipping) {
  51. $PSHOP_SHIPPING_MODULES = Array( "free_shipping" );
  52. include_once( CLASSPATH. "shipping/free_shipping.php" );
  53. $this->_SHIPPING = new free_shipping();
  54. }
  55. elseif( !empty( $_REQUEST['shipping_rate_id'] )) {
  56. // Create a Shipping Object and assign it to the _SHIPPING attribute
  57. // We take the first Part of the Shipping Rate Id String
  58. // which holds the Class Name of the Shipping Module
  59. $rate_array = explode( "|", urldecode(vmGet($_REQUEST,"shipping_rate_id")) );
  60. $filename = basename( $rate_array[0] );
  61. if( $filename != '' && file_exists(CLASSPATH. "shipping/".$filename.".php")) {
  62. include_once( CLASSPATH. "shipping/".$filename.".php" );
  63. if( class_exists($filename) ) {
  64. $this->_SHIPPING = new $filename();
  65. }
  66. }
  67. }
  68. //$steps = ps_checkout::get_checkout_steps();
  69. if(empty($_REQUEST['ship_to_info_id']) && ps_checkout::noShipToNecessary()) {
  70. $db = new ps_DB();
  71. /* Select all the ship to information for this user id and
  72. * order by modification date; most recently changed to oldest
  73. */
  74. $q = "SELECT user_info_id from `#__{vm}_user_info` WHERE ";
  75. $q .= "user_id='" . $_SESSION['auth']["user_id"] . "' ";
  76. $q .= "AND address_type='BT'";
  77. $db->query($q);
  78. $db->next_record();
  79. $_REQUEST['ship_to_info_id'] = $db->f("user_info_id");
  80. }
  81. }
  82. /**
  83. * Checks if Ship To can be skipped
  84. *
  85. * @return boolean
  86. */
  87. function noShipToNecessary() {
  88. global $cart, $only_downloadable_products;
  89. if( NO_SHIPTO == '1') {
  90. return true;
  91. }
  92. if( !isset( $cart)) $cart = ps_cart::initCart();
  93. if( ENABLE_DOWNLOADS == '1') {
  94. $not_downloadable = false;
  95. require_once( CLASSPATH .'ps_product.php');
  96. for($i = 0; $i < $cart["idx"]; $i++) {
  97. if( !ps_product::is_downloadable($cart[$i]['product_id']) ) {
  98. $not_downloadable = true;
  99. break;
  100. }
  101. }
  102. return !$not_downloadable;
  103. }
  104. return false;
  105. }
  106. function noShippingMethodNecessary() {
  107. global $cart, $only_downloadable_products;
  108. if( NO_SHIPPING == '1') {
  109. return true;
  110. }
  111. if( !isset( $cart)) $cart = ps_cart::initCart();
  112. if( ENABLE_DOWNLOADS == '1') {
  113. $not_downloadable = false;
  114. require_once( CLASSPATH .'ps_product.php');
  115. for($i = 0; $i < $cart["idx"]; $i++) {
  116. if( !ps_product::is_downloadable($cart[$i]['product_id']) ) {
  117. $not_downloadable = true;
  118. break;
  119. }
  120. }
  121. return !$not_downloadable;
  122. }
  123. return false;
  124. }
  125. function noShippingNecessary() {
  126. return $this->noShipToNecessary() && $this->noShippingMethodNecessary();
  127. }
  128. /**
  129. * Retrieve an array with all order steps and their details
  130. *
  131. * @return array
  132. */
  133. function get_checkout_steps() {
  134. global $VM_CHECKOUT_MODULES;
  135. $stepnames = array_keys( $VM_CHECKOUT_MODULES );
  136. $steps = array();
  137. $i = 0;
  138. $last_order = 0;
  139. foreach( $VM_CHECKOUT_MODULES as $step ) {
  140. // Get the stepname from the array key
  141. $stepname = current($stepnames);
  142. next($stepnames);
  143. switch( $stepname ) {
  144. case 'CHECK_OUT_GET_SHIPPING_ADDR':
  145. if( ps_checkout::noShipToNecessary() ) $step['enabled'] = 0;
  146. break;
  147. case 'CHECK_OUT_GET_SHIPPING_METHOD':
  148. if( ps_checkout::noShippingMethodNecessary() ) $step['enabled'] = 0;
  149. break;
  150. }
  151. if( $step['enabled'] == 1 ) {
  152. $steps[$step['order']][] = $stepname;
  153. }
  154. }
  155. ksort( $steps );
  156. return $steps;
  157. }
  158. /**
  159. * Retrieve the key name of the current checkout step
  160. *
  161. * @return string
  162. */
  163. function get_current_stage() {
  164. $steps = ps_checkout::get_checkout_steps();
  165. $stage = key( $steps ); // $steps is sorted by key, so the first key is the first stage
  166. // First check the REQUEST parameters for other steps
  167. if( !empty( $_REQUEST['checkout_last_step'] ) && empty( $_POST['checkout_this_step'] )) {
  168. // Make sure we have an integer (max 4)
  169. $checkout_step = abs( min( $_REQUEST['checkout_last_step'], 4 ) );
  170. if( isset( $steps[$checkout_step] )) {
  171. return $checkout_step; // it's a valid step
  172. }
  173. }
  174. $checkout_step = (int)vmGet( $_REQUEST, 'checkout_stage' );
  175. if( isset( $steps[$checkout_step] )) {
  176. return $checkout_step; // it's a valid step
  177. }
  178. // Else: we have no alternative steps given by REQUEST
  179. while ($step = current($steps)) {
  180. if( !empty($_POST['checkout_this_step']) ) {
  181. foreach( $step as $stepname ) {
  182. if( in_array( $stepname, $_POST['checkout_this_step'])) {
  183. next($steps);
  184. $key = key( $steps );
  185. if( empty( $key )) {
  186. // We are beyond the last index of the array and need to go "back" to the last index
  187. end( $steps );
  188. }
  189. //echo "Stage: ".key( $steps );
  190. return key($steps);
  191. }
  192. }
  193. }
  194. next($steps);
  195. }
  196. return $stage;
  197. }
  198. /**
  199. * Displays the "checkout bar" using the checkout bar template
  200. *
  201. * @param array $steps_to_do Array holding all steps the customer has to make
  202. * @param array $step_msg Array containing the step messages
  203. * @param int $step_count Number of steps to make
  204. * @param int $highlighted_step The index of the recent step
  205. */
  206. function show_checkout_bar($highlighted_step=null) {
  207. global $sess, $ship_to_info_id, $shipping_rate_id, $VM_LANG;
  208. if (SHOW_CHECKOUT_BAR != '1' || defined('VM_CHECKOUT_BAR_LOADED')) {
  209. return;
  210. }
  211. // Let's assemble the steps
  212. $steps = ps_checkout::get_checkout_steps();
  213. $step_count = sizeof( $steps );
  214. $steps_tmp = $steps;
  215. $i = 0;
  216. foreach( $steps as $step ) {
  217. foreach( $step as $step_name ) {
  218. switch ( $step_name ) {
  219. case 'CHECK_OUT_GET_SHIPPING_ADDR':
  220. $step_msg = $VM_LANG->_('PHPSHOP_ADD_SHIPTO_2');
  221. break;
  222. case 'CHECK_OUT_GET_SHIPPING_METHOD':
  223. $step_msg = $VM_LANG->_('PHPSHOP_ISSHIP_LIST_CARRIER_LBL');
  224. break;
  225. case 'CHECK_OUT_GET_PAYMENT_METHOD':
  226. $step_msg = $VM_LANG->_('PHPSHOP_ORDER_PRINT_PAYMENT_LBL');
  227. break;
  228. case 'CHECK_OUT_GET_FINAL_CONFIRMATION':
  229. $step_msg = $VM_LANG->_('PHPSHOP_CHECKOUT_CONF_PAYINFO_COMPORDER');
  230. break;
  231. }
  232. $steps_to_do[$i][] = array('step_name' => $step_name,
  233. 'step_msg' => $step_msg,
  234. 'step_order' => key($steps_tmp) );
  235. }
  236. next( $steps_tmp );
  237. $i++;
  238. }
  239. if( !$highlighted_step ) {
  240. $highlighted_step = ps_checkout::get_current_stage();
  241. }
  242. $theme = new $GLOBALS['VM_THEMECLASS']();
  243. $theme->set_vars( array( 'step_count' => $step_count,
  244. 'steps_to_do' => $steps_to_do,
  245. 'steps' => $steps,
  246. 'highlighted_step' => $highlighted_step,
  247. 'ship_to_info_id' => vmGet($_REQUEST, 'ship_to_info_id'),
  248. 'shipping_rate_id' => vmGet( $_REQUEST, 'shipping_rate_id')
  249. ) );
  250. echo $theme->fetch( 'checkout/checkout_bar.tpl.php');
  251. define('VM_CHECKOUT_BAR_LOADED', 1 );
  252. }
  253. /**
  254. * Called to validate the form values before the order is stored
  255. *
  256. * @author gday
  257. * @author soeren
  258. *
  259. * @param array $d
  260. * @return boolean
  261. */
  262. function validate_form(&$d) {
  263. global $VM_LANG, $PSHOP_SHIPPING_MODULES, $vmLogger;
  264. $db = new ps_DB;
  265. $auth = $_SESSION['auth'];
  266. $cart = $_SESSION['cart'];
  267. if (!$cart["idx"]) {
  268. $q = "SELECT order_id FROM #__{vm}_orders WHERE user_id='" . $auth["user_id"] . "' ";
  269. $q .= "ORDER BY cdate DESC";
  270. $db->query($q);
  271. $db->next_record();
  272. $d["order_id"] = $db->f("order_id");
  273. return False;
  274. }
  275. if( PSHOP_AGREE_TO_TOS_ONORDER == '1' ) {
  276. if( empty( $d["agreed"] )) {
  277. $vmLogger->warning( $VM_LANG->_('PHPSHOP_AGREE_TO_TOS',false) );
  278. return false;
  279. }
  280. }
  281. if ( !ps_checkout::noShippingMethodNecessary() ) {
  282. if ( !$this->validate_shipping_method($d) ) {
  283. return False;
  284. }
  285. }
  286. if ( !$this->validate_payment_method( $d, false )) {
  287. return false;
  288. }
  289. if( CHECK_STOCK == '1' ) {
  290. for($i = 0; $i < $cart["idx"]; $i++) {
  291. $quantity_in_stock = ps_product::get_field($cart[$i]["product_id"], 'product_in_stock');
  292. $product_name = ps_product::get_field($cart[$i]["product_id"], 'product_name');
  293. if( $cart[$i]["quantity"] > $quantity_in_stock ) {
  294. $vmLogger->err( 'The Quantity for the Product "'.$product_name.'" in your Cart ('.$cart[$i]["quantity"].') exceeds the Quantity in Stock ('.$quantity_in_stock.').
  295. We are very sorry for this Inconvenience, but you you need to lower the Quantity in Cart for this Product.');
  296. return false;
  297. }
  298. }
  299. }
  300. // calculate the unix timestamp for the specified expiration date
  301. // default the day to the 1st
  302. $expire_timestamp = @mktime(0,0,0,$_SESSION["ccdata"]["order_payment_expire_month"], 15,$_SESSION["ccdata"]["order_payment_expire_year"]);
  303. $_SESSION["ccdata"]["order_payment_expire"] = $expire_timestamp;
  304. return True;
  305. }
  306. /**
  307. * Validates the variables prior to adding an order
  308. *
  309. * @param array $d
  310. * @return boolean
  311. */
  312. function validate_add(&$d) {
  313. global $auth, $VM_LANG, $vmLogger;
  314. require_once(CLASSPATH.'ps_payment_method.php');
  315. $ps_payment_method = new ps_payment_method;
  316. if( empty( $auth['user_id'] ) ) {
  317. $vmLogger->err('Sorry, but it is not possible to order without a User ID.
  318. Please contact the Store Administrator if this Error occurs again.');
  319. return false;
  320. }
  321. if (!ps_checkout::noShipToNecessary()) {
  322. if (empty($d["ship_to_info_id"])) {
  323. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_SHIPTO',false) );
  324. return False;
  325. }
  326. }
  327. /*
  328. if (!$d["payment_method_id"]) {
  329. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_MSG_4',false) );
  330. return False;
  331. }*/
  332. if ($ps_payment_method->is_creditcard(@$d["payment_method_id"])) {
  333. if (empty($_SESSION["ccdata"]["order_payment_number"])) {
  334. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_CCNR',false) );
  335. return False;
  336. }
  337. if(!$ps_payment_method->validate_payment($d["payment_method_id"],
  338. $_SESSION["ccdata"]["order_payment_number"])) {
  339. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_CCNUM_INV',false) );
  340. return False;
  341. }
  342. if(empty( $_SESSION["ccdata"]["order_payment_expire"])) {
  343. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_CCDATE_INV',false) );
  344. return False;
  345. }
  346. }
  347. return True;
  348. }
  349. function validate_shipto(&$d) {
  350. //TODO to be implemented
  351. }
  352. /**
  353. * Called to validate the shipping_method
  354. *
  355. * @param array $d
  356. * @return boolean
  357. */
  358. function validate_shipping_method(&$d) {
  359. global $VM_LANG, $PSHOP_SHIPPING_MODULES, $vmLogger;
  360. if( empty($d['shipping_rate_id']) ) {
  361. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_SHIP',false) );
  362. return false;
  363. }
  364. if( is_callable( array($this->_SHIPPING, 'validate') )) {
  365. if(!$this->_SHIPPING->validate( $d )) {
  366. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_OTHER_SHIP',false) );
  367. return false;
  368. }
  369. }
  370. return true;
  371. }
  372. /**
  373. * Called to validate the payment_method
  374. * If payment with CreditCard is used, than the Data must be in stored in the session
  375. * This has be done to prevent sending the CreditCard Number back in hidden fields
  376. * If the parameter $is_test is true the Number Visa Creditcard number 4111 1111 1111 1111
  377. *
  378. * @param array $d
  379. * @param boolean $is_test
  380. * @return boolean
  381. */
  382. function validate_payment_method(&$d, $is_test) {
  383. global $VM_LANG, $vmLogger, $order_total;
  384. $auth = $_SESSION['auth'];
  385. $cart = $_SESSION['cart'];
  386. // We don't need to validate a payment method when
  387. // the user has no order total he should pay
  388. if( empty( $_REQUEST['order_total'])) {
  389. if( isset( $d['order_total'])) {
  390. if( round( $d['order_total'], 2 ) <= 0.00 ) {
  391. return true;
  392. }
  393. }
  394. if( isset($order_total) && $order_total <= 0.00 ) {
  395. return true;
  396. }
  397. }
  398. if (!isset($d["payment_method_id"]) || $d["payment_method_id"]==0 ) {
  399. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_PAYM',false) );
  400. return false;
  401. }
  402. require_once(CLASSPATH.'ps_payment_method.php');
  403. $ps_payment_method = new ps_payment_method;
  404. $dbp = new ps_DB; //DB Payment_method
  405. // Now Check if all needed Payment Information are entered
  406. // Bank Information is found in the User_Info
  407. $w = "SELECT `enable_processor` FROM `#__{vm}_payment_method` WHERE ";
  408. $w .= "payment_method_id=" . (int)$d["payment_method_id"];
  409. $dbp->query($w);
  410. $dbp->next_record();
  411. if (($dbp->f("enable_processor") == "Y")
  412. || ($dbp->f("enable_processor") == "")) {
  413. // Creditcard
  414. if (empty( $_SESSION['ccdata']['creditcard_code']) ) {
  415. $vmLogger->err( $VM_LANG->_('VM_CHECKOUT_ERR_CCTYPE') );
  416. return false;
  417. }
  418. // $_SESSION['ccdata'] = $ccdata;
  419. // The Data should be in the session
  420. if (!isset($_SESSION['ccdata'])) { //Not? Then Error
  421. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_CCDATA',false) );
  422. return False;
  423. }
  424. if (!$_SESSION['ccdata']['order_payment_number']) {
  425. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_CCNR_FOUND',false) );
  426. return False;
  427. }
  428. // CREDIT CARD NUMBER CHECK
  429. // USING THE CREDIT CARD CLASS in ps_payment
  430. if(!$ps_payment_method->validate_payment( $_SESSION['ccdata']['creditcard_code'], $_SESSION['ccdata']['order_payment_number'])) {
  431. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_CCDATE',false) );
  432. return False;
  433. }
  434. if (!$is_test) {
  435. $payment_number = preg_replace("/ |-/", "", $_SESSION['ccdata']['order_payment_number']);
  436. if ($payment_number == "4111111111111111") {
  437. $vmLogger->warning( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_TEST',false) );
  438. return False;
  439. }
  440. }
  441. if(!empty($_SESSION['ccdata']['need_card_code']) && empty($_SESSION['ccdata']['credit_card_code'])) {
  442. $vmLogger->err( $VM_LANG->_('PHPSHOP_CUSTOMER_CVV2_ERROR',false) );
  443. return False;
  444. }
  445. if(!$_SESSION['ccdata']['order_payment_expire_month']) {
  446. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_CCMON',false) );
  447. return False;
  448. }
  449. if(!$_SESSION['ccdata']['order_payment_expire_year']) {
  450. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_CCYEAR',false) );
  451. return False;
  452. }
  453. $date = getdate( time() );
  454. if ($_SESSION['ccdata']['order_payment_expire_year'] < $date["year"] or
  455. ($_SESSION['ccdata']['order_payment_expire_year'] == $date["year"] and
  456. $_SESSION['ccdata']['order_payment_expire_month'] < $date["mon"])) {
  457. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_CCDATE_INV',false) );
  458. return False;
  459. }
  460. return True;
  461. }
  462. elseif ($dbp->f("enable_processor") == "B") {
  463. $_SESSION['ccdata']['creditcard_code'] = "";
  464. $_SESSION['ccdata']['order_payment_name'] = "";
  465. $_SESSION['ccdata']['order_payment_number'] = "";
  466. $_SESSION['ccdata']['order_payment_expire_month'] = "";
  467. $_SESSION['ccdata']['order_payment_expire_year'] = "";
  468. // Bank Account
  469. require_once( CLASSPATH . 'ps_user.php' );
  470. $dbu =& ps_user::getUserInfo( $auth["user_id"], array( 'bank_account_holder','bank_iban','bank_account_nr','bank_sort_code','bank_name' ) );
  471. if ( $dbu->f("bank_account_holder") == "" || $dbu->f("bank_account_nr") =="" ) {
  472. if( !empty($d['bank_account_holder']) && !empty($d['bank_account_nr'])) {
  473. // Insert the given data
  474. $fields = array( 'bank_account_holder' => $d['bank_account_holder'],
  475. 'bank_account_nr' => $d['bank_account_nr'],
  476. 'bank_sort_code' => $d['bank_sort_code'],
  477. 'bank_name' => $d['bank_name'],
  478. 'bank_iban' => $d['bank_iban']
  479. );
  480. ps_user::setUserInfo( $fields, $auth["user_id"] );
  481. $dbu =& ps_user::getUserInfo( $auth["user_id"], array( 'bank_account_holder','bank_iban','bank_account_nr','bank_sort_code','bank_name' ) );
  482. }
  483. else {
  484. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_USER_DATA',false) );
  485. return False;
  486. }
  487. }
  488. if ($dbu->f("bank_account_holder") == ""){
  489. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_BA_HOLDER_NAME',false) );
  490. return False;
  491. }
  492. if (($dbu->f("bank_iban") == "") and
  493. ($dbu->f("bank_account_nr") =="")) {
  494. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_IBAN',false) );
  495. return False;
  496. }
  497. if ($dbu->f("bank_iban") == "") {
  498. if ($dbu->f("bank_account_nr") == ""){
  499. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_BA_NUM',false) );
  500. return False;
  501. }
  502. if ($dbu->f("bank_sort_code") == ""){
  503. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_BANK_SORT',false) );
  504. return False;
  505. }
  506. if ($dbu->f("bank_name") == ""){
  507. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_BANK_NAME',false) );
  508. return False;
  509. }
  510. }
  511. }
  512. else {
  513. $_SESSION['ccdata']['creditcard_code'] = '';
  514. $_SESSION['ccdata']['order_payment_name'] = "";
  515. $_SESSION['ccdata']['order_payment_number'] = "";
  516. $_SESSION['ccdata']['order_payment_expire_month'] = "";
  517. $_SESSION['ccdata']['order_payment_expire_year'] = "";
  518. }
  519. // Enter additional Payment check procedures here if neccessary
  520. return True;
  521. }
  522. /**
  523. * Update order details
  524. * CURRENTLY UNUSED
  525. *
  526. * @param array $d
  527. * @return boolean
  528. */
  529. function update(&$d) {
  530. global $vmLogger;
  531. $db = new ps_DB;
  532. $timestamp = time();
  533. if ($this->validate_update($d)) {
  534. return True;
  535. }
  536. else {
  537. $vmLogger->err( $this->error );
  538. return False;
  539. }
  540. }
  541. /**
  542. * Control Function for the Checkout Process
  543. * @author Ekkhard Domning
  544. * @author soeren
  545. * @param array $d
  546. * @return boolean
  547. */
  548. function process(&$d) {
  549. global $checkout_this_step, $sess,$VM_LANG, $vmLogger;
  550. $ccdata = array();
  551. if( empty($d["checkout_this_step"]) || !is_array(@$d["checkout_this_step"])) {
  552. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_VALID_STEP',false) );
  553. return false;
  554. }
  555. foreach($d["checkout_this_step"] as $checkout_this_step) {
  556. switch($checkout_this_step) {
  557. case 'CHECK_OUT_GET_FINAL_BASKET' :
  558. break;
  559. case 'CHECK_OUT_GET_SHIPPING_ADDR' :
  560. // The User has choosen a Shipping address
  561. if (empty($d["ship_to_info_id"])) {
  562. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_SHIPTO',false) );
  563. unset( $_POST['checkout_this_step']);
  564. return False;
  565. }
  566. break;
  567. case 'CHECK_OUT_GET_SHIPPING_METHOD':
  568. // The User has choosen a Shipping method
  569. if (!$this->validate_shipping_method($d)) {
  570. unset( $_POST['checkout_this_step']);
  571. return false;
  572. }
  573. break;
  574. case 'CHECK_OUT_GET_PAYMENT_METHOD':
  575. // The User has choosen a payment method
  576. $_SESSION['ccdata']['order_payment_name'] = @$d['order_payment_name'];
  577. // VISA, AMEX, DISCOVER....
  578. $_SESSION['ccdata']['creditcard_code'] = @$d['creditcard_code'];
  579. $_SESSION['ccdata']['order_payment_number'] = @$d['order_payment_number'];
  580. $_SESSION['ccdata']['order_payment_expire_month'] = @$d['order_payment_expire_month'];
  581. $_SESSION['ccdata']['order_payment_expire_year'] = @$d['order_payment_expire_year'];
  582. // 3-digit Security Code (CVV)
  583. $_SESSION['ccdata']['credit_card_code'] = @$d['credit_card_code'];
  584. if (!$this->validate_payment_method($d, false)) { //Change false to true to Let the user play with the VISA Testnumber
  585. unset( $_POST['checkout_this_step']);
  586. return false;
  587. }
  588. break;
  589. case 'CHECK_OUT_GET_FINAL_CONFIRMATION':
  590. // The User wants to order now, validate everything, if OK than Add immeditialtly
  591. return( $this->add( $d ) );
  592. default:
  593. $vmLogger->crit( "CheckOut step ($checkout_this_step) is undefined!" );
  594. return false;
  595. } // end switch
  596. }
  597. return true;
  598. } // end function process
  599. /**
  600. * Prints the List of all shipping addresses of a user
  601. *
  602. * @param unknown_type $user_id
  603. * @param unknown_type $name
  604. * @param unknown_type $value
  605. */
  606. function ship_to_addresses_radio($user_id, $name, $value) {
  607. echo ps_checkout::list_addresses( $user_id, $name, $value );
  608. }
  609. /**
  610. * Creates a Radio List of all shipping addresses of a user
  611. *
  612. * @param int $user_id
  613. * @param string $name
  614. * @param string $value
  615. */
  616. function list_addresses( $user_id, $name, $value ) {
  617. global $sess,$VM_LANG;
  618. $db = new ps_DB;
  619. /* Select all the ship to information for this user id and
  620. * order by modification date; most recently changed to oldest
  621. */
  622. $q = "SELECT * from #__{vm}_user_info WHERE ";
  623. $q .= "user_id=" . (int)$user_id . ' ';
  624. $q .= "AND address_type='BT'";
  625. $db->query($q);
  626. $db->next_record();
  627. $bt_user_info_id = $db->f("user_info_id");
  628. $q = "SELECT * FROM #__{vm}_user_info i ";
  629. $q .= "INNER JOIN #__{vm}_country c ON (i.country=c.country_3_code) ";
  630. $q .= "LEFT JOIN #__{vm}_state s ON (i.state=s.state_2_code AND s.country_id=c.country_id) ";
  631. $q .= "WHERE user_id =" . (int)$user_id . ' ';
  632. $q .= "AND address_type = 'ST' ";
  633. $q .= "ORDER by address_type_name, mdate DESC";
  634. $db->query($q);
  635. $theme = vmTemplate::getInstance();
  636. $theme->set_vars(array('db' => $db,
  637. 'user_id' => $user_id,
  638. 'name' => $name,
  639. 'value' => $value,
  640. 'bt_user_info_id' => $bt_user_info_id,
  641. )
  642. );
  643. echo $theme->fetch( 'checkout/list_shipto_addresses.tpl.php');
  644. }
  645. /**
  646. * Fetches the address information for the currently logged in user
  647. *
  648. * @param string $address_type Can be BT (Bill To) or ST (Shipto address)
  649. */
  650. function display_address($address_type='BT') {
  651. $auth = $_SESSION['auth'];
  652. $address_type = $address_type == 'BT' ? $address_type : 'ST';
  653. $db = new ps_DB;
  654. $q = "SELECT * FROM #__{vm}_user_info i ";
  655. $q .= "INNER JOIN #__{vm}_country c ON (i.country=c.country_3_code OR i.country=c.country_2_code) ";
  656. $q .= "LEFT JOIN #__{vm}_state s ON (i.state=s.state_2_code AND s.country_id=c.country_id) ";
  657. $q .= "WHERE user_id='" . $auth["user_id"] . "' ";
  658. $q .= "AND address_type='BT'";
  659. $db->query($q);
  660. $db->next_record();
  661. $theme = new $GLOBALS['VM_THEMECLASS']();
  662. $theme->set('db', $db );
  663. return $theme->fetch('checkout/customer_info.tpl.php');
  664. }
  665. /**
  666. * Lists Shipping Methods of all published Shipping Modules
  667. *
  668. * @param string $ship_to_info_id
  669. * @param string $shipping_method_id
  670. */
  671. function list_shipping_methods( $ship_to_info_id=null, $shipping_method_id=null ) {
  672. global $PSHOP_SHIPPING_MODULES, $vmLogger, $auth, $weight_total;
  673. if( empty( $ship_to_info_id )) {
  674. // Get the Bill to user_info_id
  675. $database = new ps_DB();
  676. $database->setQuery( "SELECT user_info_id FROM #__{vm}_user_info WHERE user_id=".$auth['user_id']." AND address_type='BT'" );
  677. $vars["ship_to_info_id"] = $_REQUEST['ship_to_info_id'] = $database->loadResult();
  678. } else {
  679. $vars['ship_to_info_id'] = $ship_to_info_id;
  680. }
  681. $vars['shipping_rate_id'] = $shipping_method_id;
  682. $vars["weight"] = $weight_total;
  683. $vars['zone_qty'] = vmRequest::getInt( 'zone_qty', 0 );
  684. $i = 0;
  685. $theme = new $GLOBALS['VM_THEMECLASS']();
  686. $theme->set_vars(array('vars' => $vars,
  687. 'PSHOP_SHIPPING_MODULES' => $PSHOP_SHIPPING_MODULES
  688. )
  689. );
  690. echo $theme->fetch( 'checkout/list_shipping_methods.tpl.php');
  691. }
  692. /**
  693. * Lists the payment methods of all available payment modules
  694. * @static
  695. * @param int $payment_method_id
  696. */
  697. function list_payment_methods( $payment_method_id=0 ) {
  698. global $order_total, $sess, $VM_CHECKOUT_MODULES;
  699. $ps_vendor_id = $_SESSION['ps_vendor_id'];
  700. $auth = $_SESSION['auth'];
  701. $ship_to_info_id = vmGet( $_REQUEST, 'ship_to_info_id' );
  702. $shipping_rate_id = vmGet( $_REQUEST, 'shipping_rate_id' );
  703. require_once(CLASSPATH . 'ps_payment_method.php');
  704. $ps_payment_method = new ps_payment_method;
  705. require_once( CLASSPATH. 'ps_creditcard.php' );
  706. $ps_creditcard = new ps_creditcard();
  707. $count = 0;
  708. // Do we have Credit Card Payments?
  709. $exclude_ppapi = '';
  710. if ( PAYPAL_API_DIRECT_PAYMENT_ON == 0 ) {
  711. $exclude_ppapi = "AND #__{vm}_payment_method.payment_method_code <> 'PP_API' ";
  712. }
  713. $db_cc = new ps_DB;
  714. $q = "SELECT * from #__{vm}_payment_method,#__{vm}_shopper_group WHERE ";
  715. $q .= "#__{vm}_payment_method.shopper_group_id=#__{vm}_shopper_group.shopper_group_id ";
  716. $q .= "AND (#__{vm}_payment_method.shopper_group_id='".$auth['shopper_group_id']."' ";
  717. $q .= "OR #__{vm}_shopper_group.default='1') ";
  718. $q .= "AND (enable_processor='' OR enable_processor='Y') ";
  719. $q .= "AND payment_enabled='Y' ";
  720. $q .= "AND #__{vm}_payment_method.vendor_id='$ps_vendor_id' ";
  721. $q .= $exclude_ppapi;
  722. $q .= " ORDER BY list_order";
  723. $db_cc->query($q);
  724. if ($db_cc->num_rows()) {
  725. $first_payment_method_id = $db_cc->f("payment_method_id");
  726. $count += $db_cc->num_rows();
  727. $cc_payments=true;
  728. }
  729. else {
  730. $cc_payments=false;
  731. }
  732. $db_nocc = new ps_DB;
  733. $q = "SELECT * from #__{vm}_payment_method,#__{vm}_shopper_group WHERE ";
  734. $q .= "#__{vm}_payment_method.shopper_group_id=#__{vm}_shopper_group.shopper_group_id ";
  735. $q .= "AND (#__{vm}_payment_method.shopper_group_id='".$auth['shopper_group_id']."' ";
  736. $q .= "OR #__{vm}_shopper_group.default='1') ";
  737. $q .= "AND (enable_processor='B' OR enable_processor='N' OR enable_processor='P') ";
  738. $q .= "AND payment_enabled='Y' ";
  739. $q .= "AND #__{vm}_payment_method.vendor_id='$ps_vendor_id' ";
  740. $q .= " ORDER BY list_order";
  741. $db_nocc->query($q);
  742. if ($db_nocc->next_record()) {
  743. $nocc_payments=true;
  744. $first_payment_method_id = $db_nocc->f("payment_method_id");
  745. $count += $db_nocc->num_rows();
  746. $db_nocc->reset();
  747. }
  748. else {
  749. $nocc_payments=false;
  750. }
  751. // Is PayPal API enabled
  752. $db_pp = new ps_DB;
  753. $q = "SELECT * from #__{vm}_payment_method,#__{vm}_shopper_group WHERE ";
  754. $q .= "#__{vm}_payment_method.shopper_group_id=#__{vm}_shopper_group.shopper_group_id ";
  755. $q .= "AND (#__{vm}_payment_method.shopper_group_id='".$auth['shopper_group_id']."' ";
  756. $q .= "OR #__{vm}_shopper_group.default='1') ";
  757. $q .= "AND #__{vm}_payment_method.payment_method_code = 'PP_API' ";
  758. $q .= "AND payment_enabled='Y' ";
  759. $q .= "AND #__{vm}_payment_method.vendor_id='$ps_vendor_id' ";
  760. $db_pp->query($q);
  761. if ($db_pp->next_record()) {
  762. $pp_payment=true;
  763. $first_payment_method_id = $db_pp->f("payment_method_id");
  764. } else {
  765. $pp_payment=false;
  766. }
  767. // Redirect to the last step when there's only one payment method
  768. if( $VM_CHECKOUT_MODULES['CHECK_OUT_GET_PAYMENT_METHOD']['order'] != $VM_CHECKOUT_MODULES['CHECK_OUT_GET_FINAL_CONFIRMATION']['order'] ) {
  769. // order of the following two redirections swapped by JK to ensure there is no payment method where there is no order_total
  770. if( isset($order_total) && $order_total <= 0.00 ) {
  771. // In case the order total is less than or equal zero, we don't need a payment method
  772. 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),"");
  773. }
  774. elseif ($count <= 1 && $cc_payments==false) {
  775. 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 ),"");
  776. }
  777. }
  778. $theme = new $GLOBALS['VM_THEMECLASS']();
  779. $theme->set_vars(array('db_nocc' => $db_nocc,
  780. 'db_cc' => $db_cc,
  781. 'nocc_payments' => $nocc_payments,
  782. 'payment_method_id' => $payment_method_id,
  783. 'first_payment_method_id' => $first_payment_method_id,
  784. 'count' => $count,
  785. 'cc_payments' => $cc_payments,
  786. 'ps_creditcard' => $ps_creditcard,
  787. 'ps_payment_method' => $ps_payment_method
  788. )
  789. );
  790. echo $theme->fetch( 'checkout/list_payment_methods.tpl.php');
  791. }
  792. /**
  793. * This is the main function which stores the order information in the database
  794. *
  795. * @author gday, soeren, many others!
  796. * @param array $d The REQUEST/$vars array
  797. * @return boolean
  798. */
  799. function add( &$d ) {
  800. global $order_tax_details, $afid, $VM_LANG, $auth, $my, $mosConfig_offset,
  801. $vmLogger, $vmInputFilter, $discount_factor;
  802. $ps_vendor_id = $_SESSION["ps_vendor_id"];
  803. $cart = $_SESSION['cart'];
  804. require_once(CLASSPATH. 'ps_payment_method.php' );
  805. $ps_payment_method = new ps_payment_method;
  806. require_once(CLASSPATH. 'ps_product.php' );
  807. $ps_product= new ps_product;
  808. require_once(CLASSPATH.'ps_cart.php');
  809. $ps_cart = new ps_cart;
  810. $db = new ps_DB;
  811. /* Set the order number */
  812. $order_number = $this->get_order_number();
  813. $totals = $this->calc_order_totals( $d );
  814. extract( $totals );
  815. //$timestamp = time() + ($mosConfig_offset*60*60); //Original
  816. $timestamp = time(); //Custom
  817. if (!$this->validate_form($d)) {
  818. return false;
  819. }
  820. if (!$this->validate_add($d)) {
  821. return false;
  822. }
  823. // make sure Total doesn't become negative
  824. if( $order_total < 0 ) $order_total = 0;
  825. $order_total = round( $order_total, 2);
  826. $vmLogger->debug( '-- Checkout Debug--
  827. Subtotal: '.$order_subtotal.'
  828. Taxable: '.$order_taxable.'
  829. Payment Discount: '.$payment_discount.'
  830. Coupon Discount: '.$coupon_discount.'
  831. Shipping: '.$order_shipping.'
  832. Shipping Tax : '.$order_shipping_tax.'
  833. Tax : '.$order_tax.'
  834. ------------------------
  835. Order Total: '.$order_total.'
  836. ----------------------------'
  837. );
  838. // Check to see if Payment Class File exists
  839. $payment_class = $ps_payment_method->get_field($d["payment_method_id"], "payment_class");
  840. $enable_processor = $ps_payment_method->get_field($d["payment_method_id"], "enable_processor");
  841. $d['new_order_status'] = 'P'; // This is meant to be updated by a payment modules' process_payment method
  842. if (file_exists(CLASSPATH . "payment/$payment_class.php") ) {
  843. if( !class_exists( $payment_class )) {
  844. include( CLASSPATH. "payment/$payment_class.php" );
  845. }
  846. $_PAYMENT = new $payment_class();
  847. if (!$_PAYMENT->process_payment($order_number,$order_total, $d)) {
  848. $vmLogger->err( $VM_LANG->_('PHPSHOP_PAYMENT_ERROR',false)." ($payment_class)" );
  849. $_SESSION['last_page'] = "checkout.index";
  850. $_REQUEST["checkout_next_step"] = CHECK_OUT_GET_PAYMENT_METHOD;
  851. return False;
  852. }
  853. }
  854. else {
  855. $d["order_payment_log"] = $VM_LANG->_('PHPSHOP_CHECKOUT_MSG_LOG');
  856. }
  857. // Remove the Coupon, because it is a Gift Coupon and now is used!!
  858. if( @$_SESSION['coupon_type'] == "gift" ) {
  859. $d['coupon_id'] = $_SESSION['coupon_id'];
  860. include_once( CLASSPATH.'ps_coupon.php' );
  861. ps_coupon::remove_coupon_code( $d );
  862. }
  863. // Get the IP Address
  864. if (!empty($_SERVER['REMOTE_ADDR'])) {
  865. $ip = $_SERVER['REMOTE_ADDR'];
  866. }
  867. else {
  868. $ip = 'unknown';
  869. }
  870. // Collect all fields and values to store them!
  871. $fields = array(
  872. 'user_id' => $auth["user_id"],
  873. 'vendor_id' => $ps_vendor_id,
  874. 'order_number' => $order_number,
  875. 'user_info_id' => $d["ship_to_info_id"],
  876. 'ship_method_id' => @urldecode($d["shipping_rate_id"]),
  877. 'order_total' => $order_total,
  878. 'order_subtotal' => $order_subtotal,
  879. 'order_tax' => $order_tax,
  880. 'order_tax_details' => serialize($order_tax_details),
  881. 'order_shipping' => $order_shipping,
  882. 'order_shipping_tax' => $order_shipping_tax,
  883. 'order_discount' => $payment_discount,
  884. 'coupon_discount' => $coupon_discount,
  885. 'coupon_code' => @$_SESSION['coupon_code'],
  886. 'order_currency' => $GLOBALS['product_currency'],
  887. 'order_status' => 'P',
  888. 'cdate' => $timestamp,
  889. 'mdate' => $timestamp,
  890. 'customer_note' => htmlspecialchars(vmRequest::getString('customer_note','', 'POST', 'none' ), ENT_QUOTES ),
  891. 'ip_address' => $ip
  892. );
  893. // Insert the main order information
  894. $db->buildQuery( 'INSERT', '#__{vm}_orders', $fields );
  895. $result = $db->query();
  896. $d["order_id"] = $order_id = $db->last_insert_id();
  897. if( $result === false || empty( $order_id )) {
  898. $vmLogger->crit( 'Adding the Order into the Database failed! User ID: '.$auth["user_id"] );
  899. return false;
  900. }
  901. // Insert the initial Order History.
  902. $mysqlDatetime = date("Y-m-d G:i:s", $timestamp);
  903. $fields = array(
  904. 'order_id' => $order_id,
  905. 'order_status_code' => 'P',
  906. 'date_added' => $mysqlDatetime,
  907. 'customer_notified' => 1,
  908. 'comments' => ''
  909. );
  910. $db->buildQuery( 'INSERT', '#__{vm}_order_history', $fields );
  911. $db->query();
  912. /**
  913. * Insert the Order payment info
  914. */
  915. $payment_number = str_replace(array(' ','|','-'), '', @$_SESSION['ccdata']['order_payment_number']);
  916. $d["order_payment_code"] = @$_SESSION['ccdata']['credit_card_code'];
  917. // Payment number is encrypted using mySQL encryption functions.
  918. $fields = array(
  919. 'order_id' => $order_id,
  920. 'payment_method_id' => $d["payment_method_id"],
  921. 'order_payment_log' => @$d["order_payment_log"],
  922. 'order_payment_trans_id' => $vmInputFilter->safeSQL( @$d["order_payment_trans_id"] )
  923. );
  924. if( !empty( $payment_number ) && VM_STORE_CREDITCARD_DATA == '1' ) {
  925. // Store Credit Card Information only if the Store Owner has decided to do so
  926. $fields['order_payment_code'] = $d["order_payment_code"];
  927. $fields['order_payment_expire'] = @$_SESSION["ccdata"]["order_payment_expire"];
  928. $fields['order_payment_name'] = @$_SESSION["ccdata"]["order_payment_name"];
  929. $fields['order_payment_number'] = VM_ENCRYPT_FUNCTION."( '$payment_number','" . ENCODE_KEY . "')";
  930. $specialfield = array('order_payment_number');
  931. } else {
  932. $specialfield = array();
  933. }
  934. $db->buildQuery( 'INSERT', '#__{vm}_order_payment', $fields, '', $specialfield );
  935. $db->query();
  936. /**
  937. * Insert the User Billto & Shipto Info
  938. */
  939. // First: get all the fields from the user field list to copy them from user_info into the order_user_info
  940. $fields = array();
  941. require_once( CLASSPATH . 'ps_userfield.php' );
  942. $userfields = ps_userfield::getUserFields('', false, '', true, true );
  943. foreach ( $userfields as $field ) {
  944. if ($field->name=='email') $fields[] = 'user_email';
  945. else $fields[] = $field->name;
  946. }
  947. $fieldstr = implode( ',', $fields );
  948. // Save current Bill To Address
  949. $q = "INSERT INTO `#__{vm}_order_user_info`
  950. (`order_info_id`,`order_id`,`user_id`,address_type, ".$fieldstr.") ";
  951. $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'";
  952. $db->query( $q );
  953. // Save current Ship to Address if applicable
  954. $q = "INSERT INTO `#__{vm}_order_user_info`
  955. (`order_info_id`,`order_id`,`user_id`,address_type, ".$fieldstr.") ";
  956. $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'";
  957. $db->query( $q );
  958. /**
  959. * Insert all Products from the Cart into order line items;
  960. * one row per product in the cart
  961. */
  962. $dboi = new ps_DB;
  963. for($i = 0; $i < $cart["idx"]; $i++) {
  964. $r = "SELECT product_id,product_in_stock,product_sales,product_parent_id,product_sku,product_name ";
  965. $r .= "FROM #__{vm}_product WHERE product_id='".$cart[$i]["product_id"]."'";
  966. $dboi->query($r);
  967. $dboi->next_record();
  968. $product_price_arr = $ps_product->get_adjusted_attribute_price($cart[$i]["product_id"], $cart[$i]["description"]);
  969. $product_price = $GLOBALS['CURRENCY']->convert( $product_price_arr["product_price"], $product_price_arr["product_currency"] );
  970. if( empty( $_SESSION['product_sess'][$cart[$i]["product_id"]]['tax_rate'] )) {
  971. $my_taxrate = $ps_product->get_product_taxrate($cart[$i]["product_id"] );
  972. }
  973. else {
  974. $my_taxrate = $_SESSION['product_sess'][$cart[$i]["product_id"]]['tax_rate'];
  975. }
  976. // Attribute handling
  977. $product_parent_id = $dboi->f('product_parent_id');
  978. $description = '';
  979. if( $product_parent_id > 0 ) {
  980. $db_atts = $ps_product->attribute_sql( $dboi->f('product_id'), $product_parent_id );
  981. while( $db_atts->next_record()) {
  982. $description .= $db_atts->f('attribute_name').': '.$db_atts->f('attribute_value').'; ';
  983. }
  984. }
  985. $description .= $ps_product->getDescriptionWithTax($_SESSION['cart'][$i]["description"], $dboi->f('product_id'));
  986. $product_final_price = round( ($product_price *($my_taxrate+1)), 2 );
  987. $vendor_id = $ps_vendor_id;
  988. $fields = array('order_id' => $order_id,
  989. 'user_info_id' => $d["ship_to_info_id"],
  990. 'vendor_id' => $vendor_id,
  991. 'product_id' => $cart[$i]["product_id"],
  992. 'order_item_sku' => $dboi->f("product_sku"),
  993. 'order_item_name' => $dboi->f("product_name"),
  994. 'product_quantity' => $cart[$i]["quantity"],
  995. 'product_item_price' => $product_price,
  996. 'product_final_price' => $product_final_price,
  997. 'order_item_currency' => $GLOBALS['product_currency'],
  998. 'order_status' => 'P',
  999. 'product_attribute' => $description,
  1000. 'cdate' => $timestamp,
  1001. 'mdate' => $timestamp
  1002. );
  1003. $db->buildQuery( 'INSERT', '#__{vm}_order_item', $fields );
  1004. $db->query();
  1005. // Update Stock Level and Product Sales, decrease - no matter if in stock or not!
  1006. $q = "UPDATE #__{vm}_product ";
  1007. $q .= "SET product_in_stock = product_in_stock - ".(int)$cart[$i]["quantity"];
  1008. $q .= " WHERE product_id = '" . $cart[$i]["product_id"]. "'";
  1009. $db->query($q);
  1010. $q = "UPDATE #__{vm}_product ";
  1011. $q .= "SET product_sales= product_sales + ".(int)$cart[$i]["quantity"];
  1012. $q .= " WHERE product_id='".$cart[$i]["product_id"]."'";
  1013. $db->query($q);
  1014. // Update stock of parent product, if all child products are sold, thanks Ragnar Brynjulfsson
  1015. if ($dboi->f("product_parent_id") != 0) {
  1016. $q = "SELECT COUNT(product_id) ";
  1017. $q .= "FROM #__{vm}_product ";
  1018. $q .= "WHERE product_parent_id = ".$dboi->f("product_parent_id");
  1019. $q .= " AND product_in_stock > 0";
  1020. $db->query($q);
  1021. $db->next_record();
  1022. if (!$db->f("COUNT(product_id)")) {
  1023. $q = "UPDATE #__{vm}_product ";
  1024. $q .= "SET product_in_stock = 0 ";
  1025. $q .= "WHERE product_id = ".$dboi->f("product_parent_id")." LIMIT 1";
  1026. $db->query($q);
  1027. }
  1028. }
  1029. }
  1030. ######## BEGIN DOWNLOAD MOD ###############
  1031. if( ENABLE_DOWNLOADS == "1" ) {
  1032. require_once( CLASSPATH.'ps_order.php');
  1033. for($i = 0; $i < $cart["idx"]; $i++) {
  1034. // only handle downloadable products here
  1035. if( ps_product::is_downloadable($cart[$i]["product_id"])) {
  1036. $params = array('product_id' => $cart[$i]["product_id"], 'order_id' => $order_id, 'user_id' => $auth["user_id"] );
  1037. ps_order::insert_downloads_for_product( $params );
  1038. if( @VM_DOWNLOADABLE_PRODUCTS_KEEP_STOCKLEVEL == '1' ) {
  1039. // Update the product stock level back to where it was.
  1040. $q = "UPDATE #__{vm}_product ";
  1041. $q .= "SET product_in_stock = product_in_stock + ".(int)$cart[$i]["quantity"];
  1042. $q .= " WHERE product_id = '" .(int)$cart[$i]["product_id"]. "'";
  1043. $db->query($q);
  1044. }
  1045. }
  1046. }
  1047. }
  1048. ################## END DOWNLOAD MOD ###########
  1049. // Export the order_id so the checkout complete page can get it
  1050. $d["order_id"] = $order_id;
  1051. /*
  1052. * Let the shipping module know which shipping method
  1053. * was selected. This way it can save any information
  1054. * it might need later to print a shipping label.
  1055. */
  1056. if( is_callable( array($this->_SHIPPING, 'save_rate_info') )) {
  1057. $this->_SHIPPING->save_rate_info($d);
  1058. }
  1059. // Now as everything else has been done, we can update
  1060. // the Order Status if the Payment Method is
  1061. // "Use Payment Processor", because:
  1062. // Payment Processors return false on any error
  1063. // Only completed payments return true!
  1064. $update_order = false;
  1065. if( $order_total == 0.00 ) { // code moved out of $_PAYMENT check as no payment will be needed when $order_total=0.0
  1066. // If the Order Total is zero, we can confirm the order to automatically enable the download
  1067. $d['order_status'] = ENABLE_DOWNLOAD_STATUS;
  1068. $update_order = true;
  1069. } elseif (isset($_PAYMENT)) {
  1070. if( $enable_processor == "Y" || stristr($_PAYMENT->payment_code, '_API' ) !== false ) {
  1071. if( $d['new_order_status'] != 'P' ) {
  1072. $d['order_status'] = $d['new_order_status'];
  1073. $update_order = true;
  1074. } elseif( defined($_PAYMENT->payment_code.'_VERIFIED_STATUS')) {
  1075. $d['order_status'] = constant($_PAYMENT->payment_code.'_VERIFIED_STATUS');
  1076. $update_order = true;
  1077. }
  1078. }
  1079. }
  1080. if ( $update_order ) {
  1081. require_once(CLASSPATH."ps_order.php");
  1082. $ps_order = new ps_order();
  1083. $ps_order->order_status_update($d);
  1084. }
  1085. // Send the e-mail confirmation messages
  1086. $this->email_receipt($order_id);
  1087. // Reset the cart (=empty it)
  1088. $ps_cart->reset();
  1089. $_SESSION['savedcart']['idx']=0;
  1090. $ps_cart->saveCart();
  1091. // Unset the payment_method variables
  1092. $d["payment_method_id"] = "";
  1093. $d["order_payment_number"] = "";
  1094. $d["order_payment_expire"] = "";
  1095. $d["order_payment_name"] = "";
  1096. $d["credit_card_code"] = "";
  1097. // Clear the sensitive Session data
  1098. $_SESSION['ccdata']['order_payment_name'] = "";
  1099. $_SESSION['ccdata']['order_payment_number'] = "";
  1100. $_SESSION['ccdata']['order_payment_expire_month'] = "";
  1101. $_SESSION['ccdata']['order_payment_expire_year'] = "";
  1102. $_SESSION['ccdata']['credit_card_code'] = "";
  1103. $_SESSION['coupon_discount'] = "";
  1104. $_SESSION['coupon_id'] = "";
  1105. $_SESSION['coupon_redeemed'] = false;
  1106. $_POST["payment_method_id"] = "";
  1107. $_POST["order_payment_number"] = "";
  1108. $_POST["order_payment_expire"] = "";
  1109. $_POST["order_payment_name"] = "";
  1110. /*
  1111. if( empty($my->id) && !empty( $auth['user_id'])) {
  1112. require_once(CLASSPATH.'ps_user.php');
  1113. ps_user::logout();
  1114. }
  1115. */
  1116. return True;
  1117. }
  1118. /**
  1119. * Create an order number using the session id, session
  1120. * name, and the current unix timestamp.
  1121. *
  1122. * @return string
  1123. */
  1124. function get_order_number() {
  1125. global $auth;
  1126. /* Generated a unique order number */
  1127. $str = session_id();
  1128. $str .= (string)time();
  1129. $order_number = $auth['user_id'] .'_'. md5($str);
  1130. return substr($order_number, 0, 32);
  1131. }
  1132. /**
  1133. * Stores the md5 hash of the recent cart in the var _cartHash
  1134. *
  1135. */
  1136. function generate_cart_hash() {
  1137. $this->_cartHash = $this->get_new_cart_hash();
  1138. }
  1139. function get_order_total( &$d ) {
  1140. global $discount_factor;
  1141. $totals = $this->calc_order_totals($d);
  1142. return $totals['order_total'];
  1143. }
  1144. /**
  1145. * Calculates the current order totals and fills an array with all the values
  1146. *
  1147. * @param array $d
  1148. * @return array
  1149. */
  1150. function calc_order_totals( &$d ) {
  1151. global $discount_factor, $mosConfig_offset;
  1152. $totals = array();
  1153. /* sets _subtotal */
  1154. $totals['order_subtotal'] = $tmp_subtotal = $this->calc_order_subtotal($d);
  1155. $totals['order_taxable'] = $this->calc_order_taxable($d);
  1156. if( !empty($d['payment_method_id'])) {
  1157. $totals['payment_discount'] = $d['payment_discount'] = $this->get_payment_discount($d['payment_method_id'], $totals['order_subtotal']);
  1158. } else {
  1159. $totals['payment_discount'] = $d['payment_discount'] = 0.00;
  1160. }
  1161. /* DISCOUNT HANDLING */
  1162. if( !empty($_SESSION['coupon_discount']) ) {
  1163. $totals['coupon_discount'] = floatval($_SESSION['coupon_discount']);
  1164. }
  1165. else {
  1166. $totals['coupon_discount'] = 0.00;
  1167. }
  1168. // make sure Total doesn't become negative
  1169. if( $tmp_subtotal < 0 ) $totals['order_subtotal'] = $tmp_subtotal = 0;
  1170. if( $totals['order_taxable'] < 0 ) $totals['order_taxable'] = 0;
  1171. // from now on we have $order_tax_details
  1172. $d['order_tax'] = $totals['order_tax'] = round( $this->calc_order_tax($totals['order_taxable'], $d), 2 );
  1173. if( is_object($this->_SHIPPING) ) {
  1174. /* sets _shipping */
  1175. $d['order_shipping'] = $totals['order_shipping'] = round( $this->calc_order_shipping( $d ), 2 );
  1176. /* sets _shipping_tax
  1177. * btw: This is WEIRD! To get an exactly rounded value we have to convert
  1178. * the amount to a String and call "round" with the string. */
  1179. $d['order_shipping_tax'] = $totals['order_shipping_tax'] = round( strval($this->calc_order_shipping_tax($d)), 2 );
  1180. }
  1181. else {
  1182. $d['order_shipping'] = $totals['order_shipping'] = $totals['order_shipping_tax'] = $d['order_shipping_tax'] = 0.00;
  1183. }
  1184. $d['order_total'] = $totals['order_total'] = $tmp_subtotal
  1185. + $totals['order_tax']
  1186. + $totals['order_shipping']
  1187. + $totals['order_shipping_tax']
  1188. - $totals['coupon_discount']
  1189. - $totals['payment_discount'];
  1190. $totals['order_tax'] *= $discount_factor;
  1191. return $totals;
  1192. }
  1193. /**
  1194. * Generates the md5 hash of the recent cart / checkout constellation
  1195. *
  1196. * @return unknown
  1197. */
  1198. function get_new_cart_hash() {
  1199. return md5( print_r( $_SESSION['cart'], true)
  1200. . vmGet($_REQUEST,'shipping_rate_id')
  1201. . vmGet($_REQUEST,'payment_method_id')
  1202. );
  1203. }
  1204. /**
  1205. * Returns the recent subtotal
  1206. *
  1207. * @param array $d
  1208. * @return float The current order subtotal
  1209. */
  1210. function get_order_subtotal( &$d ) {
  1211. if( $this->_subtotal === null ) {
  1212. $this->_subtotal = $this->calc_order_subtotal( $d );
  1213. }
  1214. else {
  1215. if( $this->_cartHash != $this->get_new_cart_hash() ) {
  1216. // Need to re-calculate the subtotal
  1217. $this->_subtotal = $this->calc_order_subtotal( $d );
  1218. }
  1219. }
  1220. return $this->_subtotal;
  1221. }
  1222. /**************************************************************************
  1223. ** name: calc_order_subtotal()
  1224. ** created by: gday
  1225. ** description: Calculate the order subtotal for the current order.
  1226. ** Does not include tax or shipping charges.
  1227. ** parameters: $d
  1228. ** returns: sub total for this order
  1229. ***************************************************************************/
  1230. function calc_order_subtotal( &$d ) {
  1231. global $order_tax_details;
  1232. $order_tax_details = array();
  1233. $d['order_subtotal_withtax'] = 0;
  1234. $d['payment_discount'] = 0;
  1235. $auth = $_SESSION['auth'];
  1236. $cart = $_SESSION['cart'];
  1237. $order_subtotal = 0;
  1238. require_once(CLASSPATH.'ps_product.php');
  1239. $ps_product= new ps_product;
  1240. for($i = 0; $i < $cart["idx"]; $i++) {
  1241. $my_taxrate = $ps_product->get_product_taxrate($cart[$i]["product_id"] );
  1242. $price = $ps_product->get_adjusted_attribute_price($cart[$i]["product_id"], $cart[$i]["description"]);
  1243. $product_price = $product_price_tmp = $GLOBALS['CURRENCY']->convert( $price["product_price"], @$price["product_currency"] );
  1244. if( $auth["show_price_including_tax"] == 1 ) {
  1245. $product_price = round( ($product_price *($my_taxrate+1)), 2 );
  1246. $product_price *= $cart[$i]["quantity"];
  1247. $d['order_subtotal_withtax'] += $product_price;
  1248. $product_price = $product_price /($my_taxrate+1);
  1249. $order_subtotal += $product_price;
  1250. }
  1251. else {
  1252. $order_subtotal += $product_price * $cart[$i]["quantity"];
  1253. $product_price = round( ($product_price *($my_taxrate+1)), 2 );
  1254. $product_price *= $cart[$i]["quantity"];
  1255. $d['order_subtotal_withtax'] += $product_price;
  1256. $product_price = $product_price /($my_taxrate+1);
  1257. }
  1258. if( MULTIPLE_TAXRATES_ENABLE ) {
  1259. // Calculate the amounts for each tax rate
  1260. if( !isset( $order_tax_details[$my_taxrate] )) {
  1261. $order_tax_details[$my_taxrate] = 0;
  1262. }
  1263. $order_tax_details[$my_taxrate] += $product_price_tmp*$my_taxrate*$cart[$i]["quantity"];
  1264. }
  1265. }
  1266. return($order_subtotal);
  1267. }
  1268. /**
  1269. * Calculates the taxable order subtotal for the order.
  1270. * If an item has no weight, it is non taxable.
  1271. * @author Chris Coleman
  1272. * @param array $d
  1273. * @return float Subtotal
  1274. */
  1275. function calc_order_taxable($d) {
  1276. $auth = $_SESSION['auth'];
  1277. $cart = $_SESSION['cart'];
  1278. $subtotal = 0.0;
  1279. require_once(CLASSPATH.'ps_product.php');
  1280. $ps_product= new ps_product;
  1281. require_once(CLASSPATH.'ps_shipping_method.php');
  1282. $db = new ps_DB;
  1283. for($i = 0; $i < $cart["idx"]; $i++) {
  1284. $skip_tax = false; // do we skip this product due to zero percent tax rate?
  1285. $tax_rate_id = $ps_product->get_field($cart[$i]["product_id"],'product_tax_id');
  1286. if($tax_rate_id != '0'){
  1287. // look up the tax…

Large files files are truncated, but you can click here to view the full file