PageRenderTime 42ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

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

https://bitbucket.org/dgough/annamaria-daneswood-25102012
PHP | 2545 lines | 1679 code | 381 blank | 485 comment | 361 complexity | f85fbf354a3c8b6a921b904dbf3d7aeb MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
  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 1451 2008-07-04 19:55:31Z soeren_nb $
  6. * @package VirtueMart
  7. * @subpackage classes
  8. * @copyright Copyright (C) 2004-2008 soeren - 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.
  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 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 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() {
  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. $highlighted_step = ps_checkout::get_current_stage();
  240. $theme = new $GLOBALS['VM_THEMECLASS']();
  241. $theme->set_vars( array( 'step_count' => $step_count,
  242. 'steps_to_do' => $steps_to_do,
  243. 'steps' => $steps,
  244. 'highlighted_step' => $highlighted_step,
  245. 'ship_to_info_id' => vmGet($_REQUEST, 'ship_to_info_id'),
  246. 'shipping_rate_id' => vmGet( $_REQUEST, 'shipping_rate_id')
  247. ) );
  248. echo $theme->fetch( 'checkout/checkout_bar.tpl.php');
  249. define('VM_CHECKOUT_BAR_LOADED', 1 );
  250. }
  251. /**
  252. * Called to validate the form values before the order is stored
  253. *
  254. * @author gday
  255. * @author soeren
  256. *
  257. * @param array $d
  258. * @return boolean
  259. */
  260. function validate_form(&$d) {
  261. global $VM_LANG, $PSHOP_SHIPPING_MODULES, $vmLogger;
  262. $db = new ps_DB;
  263. $auth = $_SESSION['auth'];
  264. $cart = $_SESSION['cart'];
  265. if (!$cart["idx"]) {
  266. $q = "SELECT order_id FROM #__{vm}_orders WHERE user_id='" . $auth["user_id"] . "' ";
  267. $q .= "ORDER BY cdate DESC";
  268. $db->query($q);
  269. $db->next_record();
  270. $d["order_id"] = $db->f("order_id");
  271. return False;
  272. }
  273. if( PSHOP_AGREE_TO_TOS_ONORDER == '1' ) {
  274. if( empty( $d["agreed"] )) {
  275. $vmLogger->warning( $VM_LANG->_('PHPSHOP_AGREE_TO_TOS',false) );
  276. return false;
  277. }
  278. }
  279. if ( !ps_checkout::noShippingMethodNecessary() ) {
  280. if ( !$this->validate_shipping_method($d) ) {
  281. return False;
  282. }
  283. }
  284. if ( !$this->validate_payment_method( $d, false )) {
  285. return false;
  286. }
  287. if( CHECK_STOCK == '1' ) {
  288. for($i = 0; $i < $cart["idx"]; $i++) {
  289. $quantity_in_stock = ps_product::get_field($cart[$i]["product_id"], 'product_in_stock');
  290. $product_name = ps_product::get_field($cart[$i]["product_id"], 'product_name');
  291. if( $cart[$i]["quantity"] > $quantity_in_stock ) {
  292. $vmLogger->err( 'The Quantity for the Product "'.$product_name.'" in your Cart ('.$cart[$i]["quantity"].') exceeds the Quantity in Stock ('.$quantity_in_stock.').
  293. We are very sorry for this Inconvenience, but you you need to lower the Quantity in Cart for this Product.');
  294. return false;
  295. }
  296. }
  297. }
  298. return True;
  299. }
  300. /**
  301. * Validates the variables prior to adding an order
  302. *
  303. * @param array $d
  304. * @return boolean
  305. */
  306. function validate_add(&$d) {
  307. global $auth, $VM_LANG, $vmLogger;
  308. require_once(CLASSPATH.'ps_payment_method.php');
  309. $ps_payment_method = new ps_payment_method;
  310. if( empty( $auth['user_id'] ) ) {
  311. $vmLogger->err('Sorry, but it is not possible to order without a User ID.
  312. Please contact the Store Administrator if this Error occurs again.');
  313. return false;
  314. }
  315. if (!ps_checkout::noShipToNecessary()) {
  316. if (empty($d["ship_to_info_id"])) {
  317. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_SHIPTO',false) );
  318. return False;
  319. }
  320. }
  321. /*
  322. if (!$d["payment_method_id"]) {
  323. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_MSG_4',false) );
  324. return False;
  325. }*/
  326. if ($ps_payment_method->is_creditcard(@$d["payment_method_id"])) {
  327. if (empty($_SESSION["ccdata"]["order_payment_number"])) {
  328. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_CCNR',false) );
  329. return False;
  330. }
  331. if(!$ps_payment_method->validate_payment($d["payment_method_id"],
  332. $_SESSION["ccdata"]["order_payment_number"])) {
  333. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_CCNUM_INV',false) );
  334. return False;
  335. }
  336. if(empty($_SESSION['ccdata']['order_payment_expire'])) {
  337. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_CCDATE_INV',false) );
  338. return False;
  339. }
  340. }
  341. return True;
  342. }
  343. function validate_shipto(&$d) {
  344. //TODO to be implemented
  345. }
  346. /**
  347. * Called to validate the shipping_method
  348. *
  349. * @param array $d
  350. * @return boolean
  351. */
  352. function validate_shipping_method(&$d) {
  353. global $VM_LANG, $PSHOP_SHIPPING_MODULES, $vmLogger;
  354. if( empty($d['shipping_rate_id']) ) {
  355. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_SHIP',false) );
  356. return false;
  357. }
  358. if( is_callable( array($this->_SHIPPING, 'validate') )) {
  359. if(!$this->_SHIPPING->validate( $d )) {
  360. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_OTHER_SHIP',false) );
  361. return false;
  362. }
  363. }
  364. return true;
  365. }
  366. /**
  367. * Called to validate the payment_method
  368. * If payment with CreditCard is used, than the Data must be in stored in the session
  369. * This has be done to prevent sending the CreditCard Number back in hidden fields
  370. * If the parameter $is_test is true the Number Visa Creditcard number 4111 1111 1111 1111
  371. *
  372. * @param array $d
  373. * @param boolean $is_test
  374. * @return boolean
  375. */
  376. function validate_payment_method(&$d, $is_test) {
  377. global $VM_LANG, $vmLogger, $order_total;
  378. $auth = $_SESSION['auth'];
  379. $cart = $_SESSION['cart'];
  380. // We don't need to validate a payment method when
  381. // the user has no order total he should pay
  382. if( empty( $_REQUEST['order_total'])) {
  383. if( isset( $d['order_total'])) {
  384. if( round( $d['order_total'], 2 ) <= 0.00 ) {
  385. return true;
  386. }
  387. }
  388. if( isset($order_total) && $order_total <= 0.00 ) {
  389. return true;
  390. }
  391. }
  392. if (!isset($d["payment_method_id"]) || $d["payment_method_id"]==0 ) {
  393. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_PAYM',false) );
  394. return false;
  395. }
  396. require_once(CLASSPATH.'ps_payment_method.php');
  397. $ps_payment_method = new ps_payment_method;
  398. $dbp = new ps_DB; //DB Payment_method
  399. // Now Check if all needed Payment Information are entered
  400. // Bank Information is found in the User_Info
  401. $w = "SELECT `enable_processor` FROM `#__{vm}_payment_method` WHERE ";
  402. $w .= "payment_method_id=" . (int)$d["payment_method_id"];
  403. $dbp->query($w);
  404. $dbp->next_record();
  405. if (($dbp->f("enable_processor") == "Y")
  406. || ($dbp->f("enable_processor") == "")) {
  407. // Creditcard
  408. if (empty( $_SESSION['ccdata']['creditcard_code']) ) {
  409. $vmLogger->err( $VM_LANG->_('VM_CHECKOUT_ERR_CCTYPE') );
  410. return false;
  411. }
  412. // $_SESSION['ccdata'] = $ccdata;
  413. // The Data should be in the session
  414. if (!isset($_SESSION['ccdata'])) { //Not? Then Error
  415. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_CCDATA',false) );
  416. return False;
  417. }
  418. if (!$_SESSION['ccdata']['order_payment_number']) {
  419. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_CCNR_FOUND',false) );
  420. return False;
  421. }
  422. // CREDIT CARD NUMBER CHECK
  423. // USING THE CREDIT CARD CLASS in ps_payment
  424. if(!$ps_payment_method->validate_payment( $_SESSION['ccdata']['creditcard_code'], $_SESSION['ccdata']['order_payment_number'])) {
  425. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_CCDATE',false) );
  426. return False;
  427. }
  428. if (!$is_test) {
  429. $payment_number = ereg_replace(" |-", "", $_SESSION['ccdata']['order_payment_number']);
  430. if ($payment_number == "4111111111111111") {
  431. $vmLogger->warning( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_TEST',false) );
  432. return False;
  433. }
  434. }
  435. if(!empty($_SESSION['ccdata']['need_card_code']) && empty($_SESSION['ccdata']['credit_card_code'])) {
  436. $vmLogger->err( $VM_LANG->_('PHPSHOP_CUSTOMER_CVV2_ERROR',false) );
  437. return False;
  438. }
  439. if(!$_SESSION['ccdata']['order_payment_expire_month']) {
  440. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_CCMON',false) );
  441. return False;
  442. }
  443. if(!$_SESSION['ccdata']['order_payment_expire_year']) {
  444. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_CCYEAR',false) );
  445. return False;
  446. }
  447. $date = getdate( time() );
  448. if ($_SESSION['ccdata']['order_payment_expire_year'] < $date["year"] or
  449. ($_SESSION['ccdata']['order_payment_expire_year'] == $date["year"] and
  450. $_SESSION['ccdata']['order_payment_expire_month'] < $date["mon"])) {
  451. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_CCDATE_INV',false) );
  452. return False;
  453. }
  454. return True;
  455. }
  456. elseif ($dbp->f("enable_processor") == "B") {
  457. $_SESSION['ccdata']['creditcard_code'] = "";
  458. $_SESSION['ccdata']['order_payment_name'] = "";
  459. $_SESSION['ccdata']['order_payment_number'] = "";
  460. $_SESSION['ccdata']['order_payment_expire_month'] = "";
  461. $_SESSION['ccdata']['order_payment_expire_year'] = "";
  462. // Bank Account
  463. require_once( CLASSPATH . 'ps_user.php' );
  464. $dbu =& ps_user::getUserInfo( $auth["user_id"], array( 'bank_account_holder','bank_iban','bank_account_nr','bank_sort_code','bank_name' ) );
  465. if($_SERVER['REMOTE_ADDR'] == '67.161.25.236'){
  466. }
  467. //Organic Mod: We want it to replace if fields are filled in
  468. //if ( $dbu->f("bank_account_holder") == "" || $dbu->f("bank_account_nr") =="" ) {
  469. if( !empty($d['bank_account_holder']) && !empty($d['bank_account_nr'])) {
  470. // Insert the given data
  471. $fields = array( 'bank_account_holder' => $d['bank_account_holder'],
  472. 'bank_account_nr' => $d['bank_account_nr'],
  473. 'bank_sort_code' => $d['bank_sort_code'],
  474. 'bank_name' => $d['bank_name'],
  475. 'bank_iban' => $d['bank_iban']
  476. );
  477. ps_user::setUserInfo( $fields, $auth["user_id"] );
  478. $dbu =& ps_user::getUserInfo( $auth["user_id"], array( 'bank_account_holder','bank_iban','bank_account_nr','bank_sort_code','bank_name' ) );
  479. }
  480. else {
  481. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_USER_DATA',false) );
  482. return False;
  483. }
  484. //}
  485. if ($dbu->f("bank_account_holder") == ""){
  486. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_BA_HOLDER_NAME',false) );
  487. return False;
  488. }
  489. if (($dbu->f("bank_iban") == "") and
  490. ($dbu->f("bank_account_nr") =="")) {
  491. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_IBAN',false) );
  492. return False;
  493. }
  494. if ($dbu->f("bank_iban") == "") {
  495. if ($dbu->f("bank_account_nr") == ""){
  496. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_BA_NUM',false) );
  497. return False;
  498. }
  499. if ($dbu->f("bank_sort_code") == ""){
  500. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_BANK_SORT',false) );
  501. return False;
  502. }
  503. if ($dbu->f("bank_name") == ""){
  504. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_BANK_NAME',false) );
  505. return False;
  506. }
  507. }
  508. }
  509. else {
  510. $_SESSION['ccdata']['creditcard_code'] = '';
  511. $_SESSION['ccdata']['order_payment_name'] = "";
  512. $_SESSION['ccdata']['order_payment_number'] = "";
  513. $_SESSION['ccdata']['order_payment_expire_month'] = "";
  514. $_SESSION['ccdata']['order_payment_expire_year'] = "";
  515. }
  516. // Enter additional Payment check procedures here if neccessary
  517. return True;
  518. }
  519. /**
  520. * Update order details
  521. * CURRENTLY UNUSED
  522. *
  523. * @param array $d
  524. * @return boolean
  525. */
  526. function update(&$d) {
  527. global $vmLogger;
  528. $db = new ps_DB;
  529. $timestamp = time();
  530. if ($this->validate_update($d)) {
  531. return True;
  532. }
  533. else {
  534. $vmLogger->err( $this->error );
  535. return False;
  536. }
  537. }
  538. /**
  539. * Control Function for the Checkout Process
  540. * @author Ekkhard Domning
  541. * @author soeren
  542. * @param array $d
  543. * @return boolean
  544. */
  545. function process(&$d) {
  546. global $checkout_this_step, $sess,$VM_LANG, $vmLogger;
  547. $ccdata = array();
  548. if( empty($d["checkout_this_step"]) || !is_array(@$d["checkout_this_step"])) {
  549. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_VALID_STEP',false) );
  550. return false;
  551. }
  552. foreach($d["checkout_this_step"] as $checkout_this_step) {
  553. switch($checkout_this_step) {
  554. case 'CHECK_OUT_GET_FINAL_BASKET' :
  555. break;
  556. case 'CHECK_OUT_GET_SHIPPING_ADDR' :
  557. // The User has choosen a Shipping address
  558. if (empty($d["ship_to_info_id"])) {
  559. $vmLogger->err( $VM_LANG->_('PHPSHOP_CHECKOUT_ERR_NO_SHIPTO',false) );
  560. unset( $_POST['checkout_this_step']);
  561. return False;
  562. }
  563. break;
  564. case 'CHECK_OUT_GET_SHIPPING_METHOD':
  565. // The User has choosen a Shipping method
  566. if (!$this->validate_shipping_method($d)) {
  567. unset( $_POST['checkout_this_step']);
  568. return false;
  569. }
  570. break;
  571. case 'CHECK_OUT_GET_PAYMENT_METHOD':
  572. // The User has choosen a payment method
  573. $_SESSION['ccdata']['order_payment_name'] = @$d['order_payment_name'];
  574. // VISA, AMEX, DISCOVER....
  575. $_SESSION['ccdata']['creditcard_code'] = @$d['creditcard_code'];
  576. $_SESSION['ccdata']['order_payment_number'] = @$d['order_payment_number'];
  577. $_SESSION['ccdata']['order_payment_expire_month'] = @$d['order_payment_expire_month'];
  578. $_SESSION['ccdata']['order_payment_expire_year'] = @$d['order_payment_expire_year'];
  579. // 3-digit Security Code (CVV)
  580. $_SESSION['ccdata']['credit_card_code'] = @$d['credit_card_code'];
  581. if (!$this->validate_payment_method($d, true)) { //Change false to true to Let the user play with the VISA Testnumber
  582. unset( $_POST['checkout_this_step']);
  583. return false;
  584. }
  585. break;
  586. case 'CHECK_OUT_GET_FINAL_CONFIRMATION':
  587. // The User wants to order now, validate everything, if OK than Add immeditialtly
  588. return( $this->add( $d ) );
  589. default:
  590. $vmLogger->crit( "CheckOut step ($checkout_this_step) is undefined!" );
  591. return false;
  592. } // end switch
  593. }
  594. return true;
  595. } // end function process
  596. /**
  597. * Prints the List of all shipping addresses of a user
  598. *
  599. * @param unknown_type $user_id
  600. * @param unknown_type $name
  601. * @param unknown_type $value
  602. */
  603. function ship_to_addresses_radio($user_id, $name, $value) {
  604. echo ps_checkout::list_addresses( $user_id, $name, $value );
  605. }
  606. /**
  607. * Creates a Radio List of all shipping addresses of a user
  608. *
  609. * @param int $user_id
  610. * @param string $name
  611. * @param string $value
  612. */
  613. function list_addresses( $user_id, $name, $value ) {
  614. global $sess,$VM_LANG;
  615. $db = new ps_DB;
  616. /* Select all the ship to information for this user id and
  617. * order by modification date; most recently changed to oldest
  618. */
  619. $q = "SELECT * from #__{vm}_user_info WHERE ";
  620. $q .= "user_id=" . (int)$user_id . ' ';
  621. $q .= "AND address_type='BT'";
  622. $db->query($q);
  623. $db->next_record();
  624. $bt_user_info_id = $db->f("user_info_id");
  625. $q = "SELECT * FROM #__{vm}_user_info i ";
  626. $q .= "INNER JOIN #__{vm}_country c ON (i.country=c.country_3_code) ";
  627. $q .= "LEFT JOIN #__{vm}_state s ON (i.state=s.state_2_code AND s.country_id=c.country_id) ";
  628. $q .= "WHERE user_id =" . (int)$user_id . ' ';
  629. $q .= "AND address_type = 'ST' ";
  630. $q .= "ORDER by address_type_name, mdate DESC";
  631. $db->query($q);
  632. $theme = vmTemplate::getInstance();
  633. $theme->set_vars(array('db' => $db,
  634. 'user_id' => $user_id,
  635. 'name' => $name,
  636. 'value' => $value,
  637. 'bt_user_info_id' => $bt_user_info_id,
  638. )
  639. );
  640. echo $theme->fetch( 'checkout/list_shipto_addresses.tpl.php');
  641. }
  642. /**
  643. * Fetches the address information for the currently logged in user
  644. *
  645. * @param string $address_type Can be BT (Bill To) or ST (Shipto address)
  646. */
  647. function display_address($address_type='BT') {
  648. $auth = $_SESSION['auth'];
  649. $address_type = $address_type == 'BT' ? $address_type : 'ST';
  650. $db = new ps_DB;
  651. $q = "SELECT * FROM #__{vm}_user_info i ";
  652. $q .= "INNER JOIN #__{vm}_country c ON (i.country=c.country_3_code OR i.country=c.country_2_code) ";
  653. $q .= "LEFT JOIN #__{vm}_state s ON (i.state=s.state_2_code AND s.country_id=c.country_id) ";
  654. $q .= "WHERE user_id='" . $auth["user_id"] . "' ";
  655. $q .= "AND address_type='BT'";
  656. $db->query($q);
  657. $db->next_record();
  658. $theme = new $GLOBALS['VM_THEMECLASS']();
  659. $theme->set('db', $db );
  660. return $theme->fetch('checkout/customer_info.tpl.php');
  661. }
  662. /**
  663. * Lists Shipping Methods of all published Shipping Modules
  664. *
  665. * @param string $ship_to_info_id
  666. * @param string $shipping_method_id
  667. */
  668. function list_shipping_methods( $ship_to_info_id=null, $shipping_method_id=null ) {
  669. global $PSHOP_SHIPPING_MODULES, $vmLogger, $auth, $weight_total;
  670. if( empty( $ship_to_info_id )) {
  671. // Get the Bill to user_info_id
  672. $database = new ps_DB();
  673. $database->setQuery( "SELECT user_info_id FROM #__{vm}_user_info WHERE user_id=".$auth['user_id']." AND address_type='BT'" );
  674. $vars["ship_to_info_id"] = $_REQUEST['ship_to_info_id'] = $database->loadResult();
  675. } else {
  676. $vars['ship_to_info_id'] = $ship_to_info_id;
  677. }
  678. $vars['shipping_rate_id'] = $shipping_method_id;
  679. $vars["weight"] = $weight_total;
  680. $vars['zone_qty'] = vmRequest::getInt( 'zone_qty', 0 );
  681. $i = 0;
  682. $theme = new $GLOBALS['VM_THEMECLASS']();
  683. $theme->set_vars(array('vars' => $vars,
  684. 'PSHOP_SHIPPING_MODULES' => $PSHOP_SHIPPING_MODULES
  685. )
  686. );
  687. echo $theme->fetch( 'checkout/list_shipping_methods.tpl.php');
  688. }
  689. /**
  690. * Lists the payment methods of all available payment modules
  691. * @static
  692. * @param int $payment_method_id
  693. */
  694. function list_payment_methods( $payment_method_id=0 ) {
  695. global $order_total, $sess, $VM_CHECKOUT_MODULES, $VB_STAGE_PAY_METHODS, $page, $ps_booking;
  696. $ps_vendor_id = $_SESSION['ps_vendor_id'];
  697. $auth = $_SESSION['auth'];
  698. $ship_to_info_id = vmGet( $_REQUEST, 'ship_to_info_id' );
  699. $shipping_rate_id = vmGet( $_REQUEST, 'shipping_rate_id' );
  700. require_once(CLASSPATH . 'ps_payment_method.php');
  701. $ps_payment_method = new ps_payment_method;
  702. require_once( CLASSPATH. 'ps_creditcard.php' );
  703. $ps_creditcard = new ps_creditcard();
  704. /**
  705. * VirtueBook:
  706. * Only show the payment stages relating to multi-stage payments
  707. * if we are on the order.payment_list page
  708. * */
  709. if(isset($VB_STAGE_PAY_METHODS) && count($VB_STAGE_PAY_METHODS) && $page == 'order.payment_list'){
  710. $stage_pay_methods = $VB_STAGE_PAY_METHODS;
  711. }else{
  712. $stage_pay_methods = array();
  713. }
  714. // Do we have Credit Card Payments?
  715. $db_cc = new ps_DB;
  716. $q = "SELECT * from #__{vm}_payment_method,#__{vm}_shopper_group WHERE ";
  717. $q .= "#__{vm}_payment_method.shopper_group_id=#__{vm}_shopper_group.shopper_group_id ";
  718. $q .= "AND (#__{vm}_payment_method.shopper_group_id='".$auth['shopper_group_id']."' ";
  719. $q .= "OR #__{vm}_shopper_group.default='1') ";
  720. $q .= "AND (enable_processor='' OR enable_processor='Y') ";
  721. $q .= (count($stage_pay_methods) ? "AND payment_method_id IN (".implode(',',$stage_pay_methods).") " : "AND payment_enabled='Y' ");
  722. $q .= "AND #__{vm}_payment_method.vendor_id='$ps_vendor_id' ";
  723. $q .= " ORDER BY list_order";
  724. $db_cc->query($q);
  725. if ($db_cc->num_rows()) {
  726. $cc_payments=true;
  727. }
  728. else {
  729. $cc_payments=false;
  730. }
  731. $count = 0;
  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 .= (count($stage_pay_methods) ? "AND payment_method_id IN (".implode(',',$stage_pay_methods).") " : "AND payment_enabled='Y' ");
  739. $q .= "AND #__{vm}_payment_method.vendor_id='$ps_vendor_id' ";
  740. //Only show paypal if owner booking payments if false or there is no payment id
  741. if(!$ps_booking->payment_id || @VB_OWNER_BOOKING_PAYMENTS == 0){
  742. $q .= "AND #__{vm}_payment_method.payment_class != 'ps_paypal' ";
  743. }
  744. $q .= " ORDER BY list_order";
  745. $db_nocc->query($q);
  746. if ($db_nocc->next_record()) {
  747. $nocc_payments=true;
  748. $first_payment_method_id = $db_nocc->f("payment_method_id");
  749. $count = $db_nocc->num_rows();
  750. $db_nocc->reset();
  751. }
  752. else {
  753. $nocc_payments=false;
  754. }
  755. // Redirect to the last step when there's only one payment method
  756. if( $VM_CHECKOUT_MODULES['CHECK_OUT_GET_PAYMENT_METHOD']['order'] != $VM_CHECKOUT_MODULES['CHECK_OUT_GET_FINAL_CONFIRMATION']['order'] ) {
  757. if ($count <= 1 && $cc_payments==false) {
  758. 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 ),"");
  759. }
  760. elseif( isset($order_total) && $order_total <= 0.00 ) {
  761. // In case the order total is less than or equal zero, we don't need a payment method
  762. 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),"");
  763. }
  764. }
  765. $theme = new $GLOBALS['VM_THEMECLASS']();
  766. $theme->set_vars(array('db_nocc' => $db_nocc,
  767. 'db_cc' => $db_cc,
  768. 'nocc_payments' => $nocc_payments,
  769. 'payment_method_id' => $payment_method_id,
  770. 'first_payment_method_id' => $first_payment_method_id,
  771. 'count' => $count,
  772. 'cc_payments' => $cc_payments,
  773. 'ps_creditcard' => $ps_creditcard,
  774. 'ps_payment_method' => $ps_payment_method
  775. )
  776. );
  777. echo $theme->fetch( 'checkout/list_payment_methods.tpl.php');
  778. }
  779. /**
  780. * This is the main function which stores the order information in the database
  781. *
  782. * @author gday, soeren, many others!
  783. * @param array $d The REQUEST/$vars array
  784. * @return boolean
  785. */
  786. function add( &$d ) {
  787. global $order_tax_details, $afid, $VM_LANG, $auth, $my, $mosConfig_offset,
  788. $vmLogger, $vmInputFilter, $discount_factor, $ps_booking;
  789. $ps_vendor_id = $_SESSION["ps_vendor_id"];
  790. $auth = $_SESSION['auth'];
  791. $cart = $_SESSION['cart'];
  792. require_once(CLASSPATH. 'ps_payment_method.php' );
  793. $ps_payment_method = new ps_payment_method;
  794. require_once(CLASSPATH. 'ps_product.php' );
  795. $ps_product= new ps_product;
  796. require_once(CLASSPATH.'ps_cart.php');
  797. $ps_cart = new ps_cart;
  798. if (AFFILIATE_ENABLE == '1') {
  799. require_once(CLASSPATH.'ps_affiliate.php');
  800. $ps_affiliate = new ps_affiliate;
  801. }
  802. $db = new ps_DB;
  803. //Validate the booking
  804. if (!$ps_booking->process(1,0)) {
  805. $_SESSION['last_page'] = "booking.index";
  806. $_REQUEST["checkout_next_step"] = CHECK_OUT_GET_FINAL_CONFIRMATION;
  807. return False;
  808. }
  809. /* Set the order number */
  810. $order_number = $this->get_order_number();
  811. $totals = $this->calc_order_totals( $d );
  812. extract( $totals );
  813. /**
  814. * Virtuebook: Add booking totals to order totals
  815. *
  816. */
  817. $payment_stages = $ps_booking->getStagePayment($order_total);
  818. /*** Virtuebook End ***/
  819. $timestamp = time() + ($mosConfig_offset*60*60);
  820. // calculate the unix timestamp for the specified expiration date
  821. // default the day to the 1st
  822. $expire_timestamp = @mktime(0,0,0,$_SESSION["ccdata"]["order_payment_expire_month"], 1,$_SESSION["ccdata"]["order_payment_expire_year"]);
  823. $_SESSION["ccdata"]["order_payment_expire"] = $expire_timestamp;
  824. //Check that the form validates and that the booking status is not set to 1
  825. //!$this->validate_form($d) ||
  826. if (!$ps_booking->status) {
  827. return false;
  828. }
  829. if (!$this->validate_add($d)) {
  830. return false;
  831. }
  832. // make sure Total doesn't become negative
  833. if( $order_total < 0 ) $order_total = 0;
  834. $order_total = round( $order_total, 2);
  835. $vmLogger->debug('-- Checkout Debug--
  836. Subtotal: '.$order_subtotal.'
  837. Taxable: '.$order_taxable.'
  838. Payment Discount: '.$payment_discount.'
  839. Coupon Discount: '.$coupon_discount.'
  840. Shipping: '.$order_shipping.'
  841. Shipping Tax : '.$order_shipping_tax.'
  842. Tax : '.$order_tax.'
  843. ------------------------
  844. Order Total: '.$order_total.'
  845. ----------------------------'
  846. );
  847. // Check to see if Payment Class File exists
  848. $payment_class = $ps_payment_method->get_field($d["payment_method_id"], "payment_class");
  849. $enable_processor = $ps_payment_method->get_field($d["payment_method_id"], "enable_processor");
  850. //Set a hasPaid variable that will control whether to send a success email later
  851. $hasPaid = 0;
  852. if (file_exists(CLASSPATH . "payment/$payment_class.php") ) {
  853. if( !class_exists( $payment_class )) {
  854. include( CLASSPATH. "payment/$payment_class.php" );
  855. }
  856. $_PAYMENT = new $payment_class();
  857. if (!$_PAYMENT->process_payment($order_number, $order_total_due, $d, $payment_stages)) {
  858. //$vmLogger->err( $VM_LANG->_('PHPSHOP_PAYMENT_ERROR',false)." ($payment_class)" );
  859. $_SESSION['last_page'] = "checkout.index";
  860. $_REQUEST["checkout_next_step"] = CHECK_OUT_GET_PAYMENT_METHOD;
  861. return False;
  862. }
  863. $hasPaid = 1;
  864. }
  865. else {
  866. $d["order_payment_log"] = $VM_LANG->_('PHPSHOP_CHECKOUT_MSG_LOG');
  867. }
  868. // Remove the Coupon, because it is a Gift Coupon and now is used!!
  869. if( @$_SESSION['coupon_type'] == "gift" ) {
  870. $d['coupon_id'] = $_SESSION['coupon_id'];
  871. include_once( CLASSPATH.'ps_coupon.php' );
  872. ps_coupon::remove_coupon_code( $d );
  873. }
  874. // Get the IP Address
  875. if (!empty($_SERVER['REMOTE_ADDR'])) {
  876. $ip = $_SERVER['REMOTE_ADDR'];
  877. }
  878. else {
  879. $ip = 'unknown';
  880. }
  881. // Collect all fields and values to store them!
  882. $fields = array(
  883. 'user_id' => $auth["user_id"],
  884. 'vendor_id' => $ps_vendor_id,
  885. 'order_number' => $order_number,
  886. 'user_info_id' => $d["ship_to_info_id"],
  887. 'ship_method_id' => @urldecode($d["shipping_rate_id"]),
  888. 'order_total' => $order_total,
  889. 'order_subtotal' => $order_subtotal,
  890. 'order_tax' => $order_tax,
  891. 'order_tax_details' => serialize($order_tax_details),
  892. 'order_shipping' => $order_shipping,
  893. 'order_shipping_tax' => $order_shipping_tax,
  894. 'order_discount' => $payment_discount,
  895. 'coupon_discount' => $coupon_discount,
  896. 'coupon_code' => @$_SESSION['coupon_code'],
  897. 'order_currency' => $GLOBALS['product_currency'],
  898. 'order_status' => 'P',
  899. 'cdate' => $timestamp,
  900. 'mdate' => $timestamp,
  901. 'customer_note' => htmlspecialchars(strip_tags($d['customer_note']), ENT_QUOTES ),
  902. 'ip_address' => $ip
  903. );
  904. // Insert the main order information
  905. $db->buildQuery( 'INSERT', '#__{vm}_orders', $fields );
  906. $result = $db->query();
  907. $d["order_id"] = $order_id = $db->last_insert_id();
  908. if( $result === false || empty( $order_id )) {
  909. $vmLogger->crit( 'Adding the Order into the Database failed! User ID: '.$auth["user_id"] );
  910. return false;
  911. }
  912. // Insert the initial Order History.
  913. $mysqlDatetime = date("Y-m-d G:i:s", $timestamp);
  914. $fields = array(
  915. 'order_id' => $order_id,
  916. 'order_status_code' => 'P',
  917. 'date_added' => $mysqlDatetime,
  918. 'customer_notified' => 1,
  919. 'comments' => '',
  920. 'booking_serialized' => serialize($ps_booking)
  921. );
  922. $db->buildQuery( 'INSERT', '#__{vm}_order_history', $fields );
  923. $db->query();
  924. /**
  925. * Virtuebook: Save the booking data
  926. */
  927. $fields = array('order_id' => $order_id,
  928. 'property_id' => $ps_booking->property_id,
  929. 'people' => $ps_booking->people,
  930. 'arrival' => $ps_booking->dateFrom,
  931. 'departure' => $ps_booking->dateTo,
  932. 'total' => $ps_booking->total,
  933. 'subtotal' => $ps_booking->subtotal,
  934. 'original' => $ps_booking->original,
  935. 'tax_total' => $ps_booking->tax,
  936. 'tax_state' => $ps_booking->tax_state,
  937. 'tax_resort' => $ps_booking->tax_resort,
  938. 'discounts' => $ps_booking->adv_discount['discount_total'],
  939. 'discount_details' => serialize($ps_booking->adv_discount),
  940. 'insurance' => $ps_booking->securityDeposit,
  941. 'cleaning' => $ps_booking->cleaning
  942. );
  943. $db->buildQuery( 'INSERT', '#__{vm}_order_booking', $fields );
  944. if (!$db->query()) {
  945. $vmLogger->crit( 'There was a problem saving your booking. The booking reference is: '.$order_id.'. The Error Information is: '.$db->getErrorMsg());
  946. return false;
  947. }
  948. /* Virtuebook End */
  949. /**
  950. * Insert the Order payment info
  951. */
  952. $payment_number = ereg_replace(" |-", "", @$_SESSION['ccdata']['order_payment_number']);
  953. $d["order_payment_code"] = @$_SESSION['ccdata']['credit_card_code'];
  954. /**
  955. * Virtuebook: Loop through the stage payment info
  956. */
  957. foreach($payment_stages->stages as $k => &$payment){
  958. if(is_object($payment)){
  959. // Payment number is encrypted using mySQL encryption functions.
  960. $fields = array(
  961. 'order_id' => $order_id,
  962. 'payment_amount' => $payment->payment_amount,
  963. 'payment_due' => $payment->payment_due,
  964. 'payment_stage' => $payment->payment_stage
  965. );
  966. $specialfield = array();
  967. //Check if the payment is due
  968. if($payment->is_due){
  969. $payment->payment_method_id = $d["payment_method_id"];
  970. $fields['payment_submitted'] = $payment->payment_submitted;
  971. $fields['payment_cleared'] = $payment->payment_cleared;
  972. $fields['payment_method_id'] = $payment->payment_method_id;
  973. $fields['order_payment_log'] = @$d["order_payment_log"];
  974. $fields['order_payment_trans_id'] = $vmInputFilter->safeSQL( @$d["order_payment_trans_id"] );
  975. if( !empty( $payment_number ) && VM_STORE_CREDITCARD_DATA == '1' ) {
  976. // Store Credit Card Information only if the Store Owner has decided to do so
  977. $fields['order_payment_code'] = $d["order_payment_code"];
  978. $fields['order_payment_expire'] = @$_SESSION["ccdata"]["order_payment_expire"];
  979. $fields['order_payment_name'] = @$_SESSION["ccdata"]["order_payment_name"];
  980. $fields['order_payment_number'] = VM_ENCRYPT_FUNCTION."( '$payment_number','" . ENCODE_KEY . "')";
  981. $specialfield = array('order_payment_number');
  982. }
  983. }
  984. //Add to DB
  985. $db->buildQuery( 'INSERT', '#__{vm}_order_payment', $fields, '', $specialfield );
  986. if(!$db->query()){
  987. $vmLogger->crit( 'There was a problem saving your bookings payment information. The booking reference is: '.$order_id.'. The Error Information is: '.$db->getErrorMsg());
  988. }
  989. }
  990. }
  991. //Store in the session for use in the thankyou page payment extra_info processing
  992. $_SESSION['payment_stages'] = $payment_stages;
  993. /**
  994. * Insert the User Billto & Shipto Info
  995. */
  996. // First: get all the fields from the user field list to copy them from user_info into the order_user_info
  997. $fields = array();
  998. require_once( CLASSPATH . 'ps_userfield.php' );
  999. $userfields = ps_userfield::getUserFields('', false, '', true, true );
  1000. foreach ( $userfields as $field ) {
  1001. $fields[] = $field->name;
  1002. }
  1003. $fieldstr = str_replace( 'email', 'user_email', implode( ',', $fields ));
  1004. // Save current Bill To Address
  1005. $q = "INSERT INTO `#__{vm}_order_user_info`
  1006. (`order_info_id`,`order_id`,`user_id`,address_type, ".$fieldstr.") ";
  1007. $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'";
  1008. $db->query( $q );
  1009. // Save current Ship to Address if applicable
  1010. $q = "INSERT INTO `#__{vm}_order_user_info`
  1011. (`order_info_id`,`order_id`,`user_id`,address_type, ".$fieldstr.") ";
  1012. $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'";
  1013. $db->query( $q );
  1014. /**
  1015. * Insert all Products from the Cart into order line items;
  1016. * one row per product in the cart
  1017. */
  1018. $dboi = new ps_DB;
  1019. for($i = 0; $i < $cart["idx"]; $i++) {
  1020. $r = "SELECT product_id,product_in_stock,product_sales,product_parent_id,product_sku,product_name ";
  1021. $r .= "FROM #__{vm}_product WHERE product_id='".$cart[$i]["product_id"]."'";
  1022. $dboi->query($r);
  1023. $dboi->next_record();
  1024. $product_price_arr = $ps_product->get_adjusted_attribute_price($cart[$i]["product_id"], $cart[$i]["description"]);
  1025. $product_price = $GLOBALS['CURRENCY']->convert( $product_price_arr["product_price"], $product_price_arr["product_currency"] );
  1026. if( empty( $_SESSION['product_sess'][$cart[$i]["product_id"]]['tax_rate'] )) {
  1027. $my_taxrate = $ps_product->get_product_taxrate($cart[$i]["product_id"] );
  1028. }
  1029. else {
  1030. $my_taxrate = $_SESSION['product_sess'][$cart[$i]["product_id"]]['tax_rate'];
  1031. }
  1032. // Attribute handling
  1033. $product_parent_id = $dboi->f('product_parent_id');
  1034. $description = '';
  1035. if( $product_parent_id > 0 ) {
  1036. $db_atts = $ps_product->attribute_sql( $dboi->f('product_id'), $product_parent_id );
  1037. while( $db_atts->next_record()) {
  1038. $description .= $db_atts->f('attribute_name').': '.$db_atts->f('attribute_value').'; ';
  1039. }
  1040. }
  1041. $description .= $ps_product->getDescriptionWithTax($_SESSION['cart'][$i]["description"], $dboi->f('product_id'));
  1042. $product_final_price = round( ($product_price *($my_taxrate+1)), 2 );
  1043. $vendor_id = $ps_vendor_id;
  1044. $fields = array('order_id' => $order_id,
  1045. 'user_info_id' => $d["ship_to_info_id"],
  1046. 'vendor_id' => $vendor_id,
  1047. 'product_id' => $cart[$i]["product_id"],
  1048. 'order_item_sku' => $dboi->f("product_sku"),
  1049. 'order_item_name' => $dboi->f("product_name"),
  1050. 'product_quantity' => $cart[$i]["quantity"],
  1051. 'product_item_price' => $product_price,
  1052. 'product_final_price' => $product_final_price,
  1053. 'order_item_currency' => $GLOBALS['product_currency'],
  1054. 'order_status' => 'P',
  1055. 'product_attribute' => $description,
  1056. 'cdate' => $timestamp,
  1057. 'mdate' => $timestamp
  1058. );
  1059. $db->buildQuery( 'INSERT', '#__{vm}_order_item', $fields );
  1060. $db->query();
  1061. // Update Stock Level and Product Sales, decrease - no matter if in stock or not!
  1062. $q = "UPDATE #__{vm}_product ";
  1063. $q .= "SET product_in_stock = product_in_stock - ".(int)$cart[$i]["quantity"];
  1064. $q .= " WHERE product_id = '" . $cart[$i]["product_id"]. "'";
  1065. $db->query($q);
  1066. $q = "UPDATE #__{vm}_product ";
  1067. $q .= "SET product_sales= product_sales + ".(int)$cart[$i]["quantity"];
  1068. $q .= " WHERE product_id='".$cart[$i]["product_id"]."'";
  1069. $db->query($q);
  1070. }
  1071. ######## BEGIN DOWNLOAD MOD ###############
  1072. if( ENABLE_DOWNLOADS == "1" ) {
  1073. require_once( CLASSPATH.'ps_order.php');
  1074. for($i = 0; $i < $cart["idx"]; $i++) {
  1075. $params = array('product_id' => $cart[$i]["product_id"], 'order_id' => $order_id, 'user_id' => $auth["user_id"] );
  1076. ps_order::insert_downloads_for_product( $params );
  1077. if( @VM_DOWNLOADABLE_PRODUCTS_KEEP_STOCKLEVEL == '1' ) {
  1078. // Update the product stock level back to where it was.
  1079. $q = "UPDATE #__{vm}_product ";
  1080. $q .= "SET product_in_stock = product_in_stock + ".(int)$cart[$i]["quantity"];
  1081. $q .= " WHERE product_id = '" .(int)$cart[$i]["product_id"]. "'";
  1082. $db->query($q);
  1083. }
  1084. }
  1085. }
  1086. ################## END DOWNLOAD MOD ###########
  1087. if (AFFILIATE_ENABLE == '1') {
  1088. $ps_affiliate->register_sale($order_id);
  1089. }
  1090. // Export the order_id so the checkout complete page can get it
  1091. $d["order_id"] = $order_id;
  1092. /*
  1093. * Let the shipping module know which shipping method
  1094. * was selected. This way it can save any information
  1095. * it might need later to print a shipping label.
  1096. */
  1097. if( is_callable( array($this->_SHIPPING, 'save_rate_info') )) {
  1098. $this->_SHIPPING->save_rate_info($d);
  1099. }
  1100. // Now as everything else has been done, we can update
  1101. // the Order Status if the Payment Method is
  1102. // "Use Payment Processor", because:
  1103. // Payment Processors return false on any error
  1104. // Only completed payments return true!
  1105. $update_order = false;
  1106. if( $enable_processor == "Y" || $enable_processor == 'B' ) {
  1107. if( defined($_PAYMENT->payment_code.'_VERIFIED_STATUS')) {
  1108. $d['order_status'] = constant($_PAYMENT->payment_code.'_VERIFIED_STATUS');
  1109. $update_order = true;
  1110. }
  1111. } elseif( $order_total == 0.00 ) {
  1112. // If the Order Total is zero, we can confirm the order to automatically enable the download
  1113. $d['order_status'] = ENABLE_DOWNLOAD_STATUS;
  1114. $update_order = true;
  1115. }
  1116. if ( $update_order ) {
  1117. require_once(CLASSPATH."ps_order.php");
  1118. $ps_order =& new ps_order();
  1119. $ps_order->order_status_update($d);
  1120. }
  1121. //Remove bank account details
  1122. require_once( CLASSPATH . 'ps_user.php' );
  1123. $fields = array( 'bank_account_holder' => '',
  1124. 'bank_account_nr' => '',
  1125. 'bank_sort_code' => '',
  1126. 'bank_name' => '',
  1127. 'bank_iban' => ''
  1128. );
  1129. ps_user::setUserInfo( $fields, $auth["user_id"] );
  1130. // Send the e-mail confirmation messages
  1131. $this->email_receipt($order_id, '', $hasPaid);
  1132. // Reset the cart (=empty it)
  1133. $ps_cart->reset();
  1134. $_SESSION['savedcart']['idx']=0;
  1135. $ps_cart->saveCart();
  1136. // Unset the payment_method variables
  1137. $d["payment_method_id"] = "";
  1138. $d["order_payment_number"] = "";
  1139. $d["order_payment_expire"] = "";
  1140. $d["order_payment_name"] = "";
  1141. $d["credit_card_code"] = "";
  1142. // Clear the sensitive Session data
  1143. $_SESSION['ccdata']['order_payment_name'] = "";
  1144. $_SESSION['ccdata']['order_payment_number'] = "";
  1145. $_SESSION['ccdata']['order_payment_expire_month'] = "";
  1146. $_SESSION['ccdata']['order_payment_expire_year'] = "";
  1147. $_SESSION['ccdata']['credit_card_code'] = "";
  1148. $_SESSION['coupon_discount'] = "";
  1149. $_SESSION['coupon_id'] = "";
  1150. $_SESSION['coupon_redeemed'] = false;
  1151. $_POST["payment_method_id"] = "";
  1152. $_POST["order_payment_number"] = "";
  1153. $_POST["order_payment_expire"] = "";
  1154. $_POST["order_payment_name"] = "";
  1155. //Clear the booking data from the session
  1156. $ps_booking->removeSession();
  1157. if( empty($my->id) && !empty( $auth['user_id'])) {
  1158. require_once(CLASSPATH.'ps_user.php');
  1159. ps_user::logout();
  1160. }
  1161. return True;
  1162. }
  1163. /**
  1164. * Create an order number using the session id, session
  1165. * name, and the current unix timestamp.
  1166. *
  1167. * @return string
  1168. */
  1169. function get_order_number() {
  1170. global $auth;
  1171. /* Generated a unique order number */
  1172. $str = session_id();
  1173. $str .= (string)time();
  1174. $order_number = $auth['user_id'] .'_'. md5($str);
  1175. return substr($order_number, 0, 32);
  1176. }
  1177. /**
  1178. * Stores the md5 hash of the recent cart in the var _cartHash
  1179. *
  1180. */
  1181. function generate_cart_hash() {
  1182. $this->_cartHash = $this->get_new_cart_hash();
  1183. }
  1184. function get_order_total( &$d ) {
  1185. global $discount_factor;
  1186. $totals = $this->calc_order_totals($d);
  1187. return $totals['order_total'];
  1188. }
  1189. /**
  1190. * Calculates the current order totals and fills an array with all the values
  1191. *
  1192. * @param array $d
  1193. * @return array
  1194. */
  1195. function calc_order_totals( &$d ) {
  1196. global $discount_factor, $mosConfig_offset, $ps_booking;
  1197. $totals = array();
  1198. /* sets _subtotal */
  1199. $totals['order_subtotal'] = $tmp_subtotal = $this->calc_order_subtotal($d);
  1200. $totals['order_taxable'] = $this->calc_order_taxable($d);
  1201. /* DISCOUNT HANDLING */
  1202. if( !empty($_SESSION['coupon_discount']) ) {
  1203. $totals['coupon_discount'] = floatval($_SESSION['coupon_discount']);
  1204. }
  1205. else {
  1206. $totals['coupon_discount'] = 0.00;
  1207. }
  1208. // make sure Total doesn't become negative
  1209. if( $tmp_subtotal < 0 ) $totals['order_subtotal'] = $tmp_subtotal = 0;
  1210. if( $totals['order_taxable'] < 0 ) $totals['order_taxable'] = 0;
  1211. // from now on we have $order_tax_details
  1212. $d['order_tax'] = $totals['order_tax'] = round( $this->calc_order_tax($totals['order_taxable'], $d), 2 );
  1213. if( is_object($this->_SHIPPING) ) {
  1214. /* sets _shipping */
  1215. $d['order_shipping'] = $totals['order_shipping'] = round( $this->calc_order_shipping( $d ), 2 );
  1216. /* sets _shipping_tax
  1217. * btw: This is WEIRD! To get an exactly rounded value we have to convert
  1218. * the amount to a String and call "round" with the string. */
  1219. $d['order_shipping_tax'] = $totals['order_shipping_tax'] = round( strval($this->calc_order_shipping_tax($d)), 2 );
  1220. }
  1221. else {
  1222. $d['order_shipping'] = $totals['order_shipping'] = $totals['order_shipping_tax'] = $d['order_shipping_tax'] = 0.00;
  1223. }
  1224. if( !empty($d['payment_method_id'])) {
  1225. $totals['payment_discount'] = $d['payment_discount'] = $this->get_payment_discount($d['payment_method_id'], $tmp_subtotal);
  1226. } else {
  1227. $totals['payment_discount'] = $d['payment_discount'] = 0.00;
  1228. }
  1229. $d['order_total'] = $totals['order_total'] = $tmp_subtotal
  1230. + $totals['order_tax']
  1231. + $totals['order_shipping']
  1232. + $totals['order_shipping_tax'];
  1233. /**
  1234. * Virtuebook: add on order totals
  1235. */
  1236. $totals['order_subtotal'] += $ps_booking->subtotal;
  1237. $totals['order_total'] += $ps_booking->total;
  1238. $totals['order_tax'] += $ps_booking->tax;
  1239. $totals['order_taxable'] = $ps_booking->tax > 0 || $totals['order_taxable'];
  1240. /**
  1241. * Get the payment stages
  1242. */
  1243. $payment_stages = $ps_booking->getStagePayment($order_total, $d['payment_method_id']);
  1244. if(isset($payment_stages->amount_due)){
  1245. $totals['order_total_due'] = $payment_stages->amount_due - $totals['coupon_discount'];
  1246. }else{
  1247. $totals['order_total_due'] = $totals['order_total'] = $totals['order_total'] - $this->get_payment_discount($d['payment_method_id'], $totals['order_total']) - $totals['coupon_discount'];
  1248. }
  1249. return $totals;
  1250. }
  1251. /**
  1252. * Generates the md5 hash of the recent cart / checkout constellation
  1253. *
  1254. * @return unknown
  1255. */
  1256. function get_new_cart_hash() {
  1257. return md5( print_r( $_SESSION['cart'], true)
  1258. . vmGet($_REQUEST,'shipping_rate_id')
  1259. . vmGet($_REQUEST,'payment_method_id')
  1260. );
  1261. }
  1262. /**
  1263. * Returns the recent subtotal
  1264. *
  1265. * @param array $d
  1266. * @return float The current order subtotal
  1267. */
  1268. function get_order_subtotal( &$d ) {
  1269. if( $this->_subtotal === null ) {
  1270. $this->_subtotal = $this->calc_order_subtotal( $d );
  1271. }
  1272. else {
  1273. if( $this->_cartHash != $this->get_new_cart_hash() ) {
  1274. // Need to re-calculate the subtotal
  1275. $this->_subtotal = $this->calc_order_subtotal( $d );
  1276. }
  1277. }
  1278. return $this->_subtotal;
  1279. }
  1280. /**************************************************************************
  1281. ** name: calc_order_subtotal()
  1282. ** created by: gday
  1283. ** description: Calculate the order subtotal for the current order.
  1284. ** Does not include tax or shipping charges.
  1285. ** parameters: $d
  1286. ** returns: sub total for this order
  1287. ***************************************************************************/
  1288. function calc_order_subtotal( &$d ) {
  1289. global $order_tax_details;
  1290. $order_tax_details = array();
  1291. $d['order_subtotal_withtax'] = 0;
  1292. $d['payment_discount'] = 0;
  1293. $auth = $_SESSION['auth'];
  1294. $cart = $_SESSION['cart'];
  1295. $order_subtotal = 0;
  1296. require_once(CLASSPATH.'ps_product.php');
  1297. $ps_product= new ps_product;
  1298. for($i = 0; $i < $cart["idx"]; $i++) {
  1299. $my_taxrate = $ps_product->get_product_taxrate($cart[$i]["product_id"] );
  1300. $price = $ps_product->get_adjusted_attribute_price($cart[$i]["product_id"], $cart[$i]["description"]);
  1301. $product_price = $product_price_tmp = $GLOBALS['CURRENCY']->convert( $price["product_price"], @$price["product_currency"] );
  1302. if( $auth["show_price_including_tax"] == 1 ) {
  1303. $product_price = round( ($product_price *($my_taxrate+1)), 2 );
  1304. $product_price *= $cart[$i]["quantity"];
  1305. $d['order_subtotal_withtax'] += $product_price;
  1306. $product_price = $product_price /($my_taxrate+1);
  1307. $order_subtotal += $product_price;
  1308. }
  1309. else {
  1310. $order_subtotal += $product_price * $cart[$i]["quantity"];
  1311. $product_price = round( ($product_price *($my_taxrate+1)), 2 );
  1312. $product_price *= $cart[$i]["quantity"];
  1313. $d['order_subtotal_withtax'] += $product_price;
  1314. $product_price = $product_price /($my_taxrate+1);
  1315. }
  1316. if( MULTIPLE_TAXRATES_ENABLE ) {
  1317. // Calculate the amounts for each tax rate
  1318. if( !isset( $order_tax_details[$my_taxrate] )) {
  1319. $order_tax_details[$my_taxrate] = 0;
  1320. }
  1321. $order_tax_details[$my_taxrate] += $product_price_tmp*$my_taxrate*$cart[$i]["quantity"];
  1322. }
  1323. }
  1324. return($order_subtotal);
  1325. }
  1326. /**
  1327. * Calculates the taxable order subtotal for the order.
  1328. * If an item has no weight, it is non taxable.
  1329. * @author Chris Coleman
  1330. * @param array $d
  1331. * @return float Subtotal
  1332. */
  1333. function calc_order_taxable($d) {
  1334. $auth = $_SESSION['auth'];
  1335. $cart = $_SESSION['cart'];
  1336. $subtotal = 0.0;
  1337. require_once(CLASSPATH.'ps_product.php');
  1338. $ps_product= new ps_product;
  1339. require_once(CLASSPATH.'ps_shipping_method.php');
  1340. $db = new ps_DB;
  1341. for($i = 0; $i < $cart["idx"]; $i++) {
  1342. $price = $ps_product->get_adjusted_attribute_price($cart[$i]["product_id"], $cart[$i]["description"]);
  1343. $product_price = $GLOBALS['CURRENCY']->convert( $price["product_price"], $price['product_currency'] );
  1344. $item_weight = ps_shipping_method::get_weight($cart[$i]["product_id"]) * $cart[$i]['quantity'];
  1345. if ($item_weight != 0 or TAX_VIRTUAL=='1') {
  1346. $subtotal += $product_price * $cart[$i]["quantity"];
  1347. }
  1348. }
  1349. return($subtotal);
  1350. }
  1351. /**
  1352. * Calculate the tax charges for the current order.
  1353. * You can switch the way, taxes are calculated:
  1354. * either based on the VENDOR address,
  1355. * or based on the ship-to address.
  1356. * ! Creates the global $order_tax_details
  1357. *
  1358. * @param float $order_taxable
  1359. * @param array $d
  1360. * @return float
  1361. */
  1362. function calc_order_tax($order_taxable, $d) {
  1363. global $order_tax_details, $discount_factor;
  1364. $auth = $_SESSION['auth'];
  1365. $ps_vendor_id = $_SESSION["ps_vendor_id"];
  1366. $db = new ps_DB;
  1367. $ship_to_info_id = vmGet( $_REQUEST, 'ship_to_info_id');
  1368. require_once(CLASSPATH.'ps_tax.php');
  1369. $ps_tax = new ps_tax;
  1370. $discount_factor = 1;
  1371. // Shipping address based TAX
  1372. if ( !ps_checkout::tax_based_on_vendor_address () ) {
  1373. $q = "SELECT state, country FROM #__{vm}_user_info ";
  1374. $q .= "WHERE user_info_id='".$ship_to_info_id. "'";
  1375. $db->query($q);
  1376. $db->next_record();
  1377. $state = $db->f("state");
  1378. $country = $db->f("country");
  1379. $q = "SELECT * FROM #__{vm}_tax_rate WHERE tax_country='$country' ";
  1380. if( $state ) {
  1381. $q .= "AND tax_state='$state'";
  1382. }
  1383. $db->query($q);
  1384. if ($db->next_record()) {
  1385. $rate = $order_taxable * floatval( $db->f("tax_rate") );
  1386. if (empty($rate)) {
  1387. $order_tax = 0.0;
  1388. }
  1389. else {
  1390. $order_tax = $rate;
  1391. }
  1392. }
  1393. else {
  1394. $order_tax = 0.0;
  1395. }
  1396. $order_tax_details[$db->f('tax_rate')] = $order_tax;
  1397. }
  1398. // Store Owner Address based TAX
  1399. else {
  1400. // Calculate the Tax with a tax rate for every product
  1401. $cart = $_SESSION['cart'];
  1402. $order_tax = 0.0;
  1403. $total = 0.0;
  1404. if( (!empty( $_SESSION['coupon_discount'] ) || !empty( $d['payment_discount'] ))
  1405. && PAYMENT_DISCOUNT_BEFORE == '1' ) {
  1406. // We need to recalculate the tax details when the discounts are applied
  1407. // BEFORE taxes - because they affect the product subtotals then
  1408. $order_tax_details = array();
  1409. }
  1410. require_once(CLASSPATH.'ps_product.php');
  1411. $ps_product= new ps_product;
  1412. require_once(CLASSPATH.'ps_shipping_method.php');
  1413. for($i = 0; $i < $cart["idx"]; $i++) {
  1414. $item_weight = ps_shipping_method::get_weight($cart[$i]["product_id"]) * $cart[$i]['quantity'];
  1415. if ($item_weight !=0 or TAX_VIRTUAL) {
  1416. $price = $ps_product->get_adjusted_attribute_price($cart[$i]["product_id"], $cart[$i]["description"]);
  1417. $price['product_price'] = $GLOBALS['CURRENCY']->convert( $price['product_price'], $price['product_currency']);
  1418. $tax_rate = $ps_product->get_product_taxrate($cart[$i]["product_id"]);
  1419. if( (!empty( $_SESSION['coupon_discount'] ) || !empty( $d['payment_discount'] ))
  1420. && PAYMENT_DISCOUNT_BEFORE == '1' ) {
  1421. $use_coupon_discount= @$_SESSION['coupon_discount'];
  1422. if( !empty( $_SESSION['coupon_discount'] )) {
  1423. if( $auth["show_price_including_tax"] == 1 ) {
  1424. $use_coupon_discount = $_SESSION['coupon_discount'] / ($tax_rate+1);
  1425. }
  1426. }
  1427. $factor = (100 * ($use_coupon_discount + @$d['payment_discount'])) / $this->_subtotal;
  1428. $price["product_price"] = $price["product_price"] - ($factor * $price["product_price"] / 100);
  1429. @$order_tax_details[$tax_rate] += $price["product_price"] * $tax_rate * $cart[$i]["quantity"];
  1430. }
  1431. $order_tax += $price["product_price"] * $tax_rate * $cart[$i]["quantity"];
  1432. $total += $price["product_price"] * $cart[$i]["quantity"];
  1433. }
  1434. }
  1435. if( (!empty( $_SESSION['coupon_discount'] ) || !empty( $d['payment_discount'] ))
  1436. && PAYMENT_DISCOUNT_BEFORE != '1' ) {
  1437. // Here we need to re-calculate the Discount
  1438. // because we assume the Discount is "including Tax"
  1439. $discounted_total = @$d['order_subtotal_withtax'] - @$_SESSION['coupon_discount'] - @$d['payment_discount'];
  1440. if( $discounted_total != @$d['order_subtotal_withtax'] && @$d['order_subtotal_withtax'] > 0.00) {
  1441. $discount_factor = $discounted_total / $d['order_subtotal_withtax'];
  1442. foreach( $order_tax_details as $rate => $value ) {
  1443. $order_tax_details[$rate] = $value * $discount_factor;
  1444. }
  1445. }
  1446. }
  1447. if( is_object($this->_SHIPPING) ) {
  1448. $taxrate = $this->_SHIPPING->get_tax_rate();
  1449. if( $taxrate ) {
  1450. $rate = $this->_SHIPPING->get_rate( $d );
  1451. if( $auth["show_price_including_tax"] == 1 ) {
  1452. @$order_tax_details[$taxrate] += $rate - ($rate / ($taxrate+1));
  1453. }
  1454. else {
  1455. @$order_tax_details[$taxrate] += $rate * $taxrate;
  1456. }
  1457. }
  1458. }
  1459. }
  1460. return( round( $order_tax, 2 ) );
  1461. }
  1462. /**************************************************************************
  1463. ** name: calc_order_shipping()
  1464. ** created by: soeren
  1465. ** description: Get the Shipping costs WITHOUT TAX
  1466. ** parameters: $d,
  1467. ** returns: a decimal number, excluding taxes
  1468. ***************************************************************************/
  1469. function calc_order_shipping( &$d ) {
  1470. $auth = $_SESSION['auth'];
  1471. $shipping_total = $this->_SHIPPING->get_rate( $d );
  1472. $shipping_taxrate = $this->_SHIPPING->get_tax_rate();
  1473. // When the Shipping rate is shown including Tax
  1474. // we have to extract the Tax from the Shipping Total
  1475. // before returning the value
  1476. if( $auth["show_price_including_tax"] == 1 ) {
  1477. $d['shipping_tax'] = $shipping_total - ($shipping_total / ($shipping_taxrate+1));
  1478. $d['shipping_total'] = $shipping_total - $d['shipping_tax'];
  1479. }
  1480. else {
  1481. $d['shipping_tax'] = $shipping_total * $shipping_taxrate;
  1482. $d['shipping_total'] = $shipping_total;
  1483. }
  1484. $d['shipping_tax'] = $GLOBALS['CURRENCY']->convert( $d['shipping_tax'] );
  1485. $d['shipping_total'] = $GLOBALS['CURRENCY']->convert( $d['shipping_total'] );
  1486. return $d['shipping_total'];
  1487. }
  1488. /**************************************************************************
  1489. ** name: calc_order_shipping_tax()
  1490. ** created by: Soeren
  1491. ** description: Calculate the tax for the shipping of the current order
  1492. ** Assumes that the function calc_order_shipping has been called before
  1493. ** parameters: $d
  1494. ** returns: Tax for the shipping of this order
  1495. ***************************************************************************/
  1496. function calc_order_shipping_tax($d) {
  1497. return $d['shipping_tax'];
  1498. }
  1499. /**************************************************************************
  1500. ** name: get_vendor_currency()
  1501. ** created by: gday
  1502. ** description: Get the currency type used by the $vendor_id
  1503. ** parameters: $vendor_id - vendor id to return currency type
  1504. ** returns: Currency type for this vendor
  1505. ***************************************************************************/
  1506. function get_vendor_currency($vendor_id) {
  1507. $db = new ps_DB;
  1508. $q = "SELECT vendor_currency FROM #__{vm}_vendor WHERE vendor_id='$vendor_id'";
  1509. $db->query($q);
  1510. $db->next_record();
  1511. $currency = $db->f("vendor_currency");
  1512. return($currency);
  1513. }
  1514. /**************************************************************************
  1515. ** name: get_payment_discount()
  1516. ** created by: soeren
  1517. ** description: Get the discount for the selected payment
  1518. ** parameters: $payment_method_id
  1519. ** returns: Discount as a decimal if found
  1520. ** 0 if nothing is found
  1521. ***************************************************************************/
  1522. function get_payment_discount( $payment_method_id, $subtotal = '' ) {
  1523. global $modulename;
  1524. if( empty( $payment_method_id )) {
  1525. return 0;
  1526. }
  1527. $db = new ps_DB();
  1528. //MOD ei
  1529. // There is a special payment method, which fee is depend on subtotal
  1530. // it is a type of cash on delivery
  1531. // comment soeren: Payment methods can implement their own method
  1532. // how to calculate the discount: the function "get_payment_rate"
  1533. // should return a float value from the payment class
  1534. require_once(CLASSPATH.'ps_payment_method.php');
  1535. $ps_payment_method = new ps_payment_method;
  1536. $payment_class = $ps_payment_method->get_field($payment_method_id, "payment_class");
  1537. // Check to see if Payment Class File exists
  1538. if (file_exists(CLASSPATH . "payment/$payment_class.php") ) {
  1539. require_once( CLASSPATH. "payment/$payment_class.php" );
  1540. eval( "\$_PAYMENT = new $payment_class();" );
  1541. if(is_callable(array($payment_class, 'get_payment_rate'))) {
  1542. return $_PAYMENT->get_payment_rate($subtotal);
  1543. }
  1544. }
  1545. //End of MOD ei
  1546. // If a payment method has no special way of calculating a discount,
  1547. // let's do this on our own from the payment_method_discount settings
  1548. $q = 'SELECT * FROM `#__{vm}_payment_method` WHERE payment_method_id='.$payment_method_id;
  1549. $db->query($q);$db->next_record();
  1550. $discount = $db->f('payment_method_discount');
  1551. $is_percent = $db->f('payment_method_discount_is_percent');
  1552. $page = vmGet($_REQUEST,'page');
  1553. $tmp = explode('.', $page);
  1554. $modulename = $tmp[0];
  1555. //Check when we should apply the discount
  1556. if($modulename == 'checkout' && !$db->f('payment_method_discount_checkout')) return 0;
  1557. else if($modulename == 'account' && !$db->f('payment_method_discount_stages')) return 0;
  1558. if( !$is_percent ) {
  1559. // Standard method: absolute amount
  1560. if (!empty($discount)) {
  1561. return(floatval( $GLOBALS['CURRENCY']->convert($discount)));
  1562. }
  1563. else {
  1564. return(0);
  1565. }
  1566. }
  1567. else {
  1568. if( $subtotal === '') {
  1569. $subtotal = $this->get_order_subtotal( $vars );
  1570. }
  1571. // New: percentage of the subtotal, limited by minimum and maximum
  1572. $max = $db->f('payment_method_discount_max_amount');
  1573. $min = $db->f('payment_method_discount_min_amount');
  1574. $value = (float) ($discount/100) * $subtotal;
  1575. if( abs($value) > $max && $max > 0 ) {
  1576. $value = -$max;
  1577. }
  1578. elseif( abs($value) < $min && $min > 0 ) {
  1579. $value = -$min;
  1580. }
  1581. return $value;
  1582. }
  1583. }
  1584. /**
  1585. * Create a receipt for the current order and email it to
  1586. * the customer and the vendor.
  1587. * @author gday
  1588. * @author soeren
  1589. * @param int $order_id
  1590. * @return boolean True on success, false on failure
  1591. */
  1592. function email_receipt($order_id, $subject = '', $hasPaid = 0, $email_customer = 0, $email_owner = 0, $email_vendor = 0) {
  1593. global $sess, $ps_product, $VM_LANG, $CURRENCY_DISPLAY, $vmLogger,
  1594. $mosConfig_fromname, $mosConfig_lang, $database, $ps_booking, $modulename;
  1595. $ps_vendor_id = vmGet( $_SESSION, 'ps_vendor_id', 1 );
  1596. $auth = $_SESSION["auth"];
  1597. require_once( CLASSPATH.'ps_order_status.php');
  1598. require_once( CLASSPATH.'ps_userfield.php');
  1599. require_once(CLASSPATH.'ps_product.php');
  1600. $ps_product = new ps_product;
  1601. // Connect to database and gather appropriate order information
  1602. $db = new ps_DB;
  1603. $q = "SELECT * FROM #__{vm}_orders WHERE order_id='$order_id'";
  1604. $db->query($q);
  1605. $db->next_record();
  1606. $user_id = $db->f("user_id");
  1607. $customer_note = $db->f("customer_note");
  1608. $order_status = ps_order_status::getOrderStatusName($db->f("order_status") );
  1609. $dbbt = new ps_DB;
  1610. $dbst = new ps_DB;
  1611. $qt = "SELECT * FROM #__{vm}_user_info WHERE user_id='".$user_id."' AND address_type='BT'";
  1612. $dbbt->query($qt);
  1613. $dbbt->next_record();
  1614. $qt = "SELECT * FROM #__{vm}_user_info WHERE user_info_id='". $db->f("user_info_id") . "'";
  1615. $dbst->query($qt);
  1616. $dbst->next_record();
  1617. $dbv = new ps_DB;
  1618. $qt = "SELECT * from #__{vm}_vendor ";
  1619. /* Need to decide on vendor_id <=> order relationship */
  1620. $qt .= "WHERE vendor_id = '".$ps_vendor_id."'";
  1621. $dbv->query($qt);
  1622. $dbv->next_record();
  1623. $dboi = new ps_DB;
  1624. $q_oi = "SELECT * FROM #__{vm}_product, #__{vm}_order_item, #__{vm}_orders ";
  1625. $q_oi .= "WHERE #__{vm}_product.product_id=#__{vm}_order_item.product_id ";
  1626. $q_oi .= "AND #__{vm}_order_item.order_id='$order_id' ";
  1627. $q_oi .= "AND #__{vm}_orders.order_id=#__{vm}_order_item.order_id";
  1628. $dboi->query($q_oi);
  1629. $db_payment = new ps_DB;
  1630. $q = "SELECT op.payment_method_id, pm.payment_method_name FROM #__{vm}_order_payment as op, #__{vm}_payment_method as pm
  1631. WHERE order_id='$order_id' AND op.payment_method_id=pm.payment_method_id";
  1632. $db_payment->query($q);
  1633. $db_payment->next_record();
  1634. if ($auth["show_price_including_tax"] == 1) {
  1635. $order_shipping = $db->f("order_shipping");
  1636. $order_shipping += $db->f("order_shipping_tax");
  1637. $order_shipping_tax = 0;
  1638. $order_tax = $db->f("order_tax") + $db->f("order_shipping_tax");
  1639. }
  1640. else {
  1641. $order_shipping = $db->f("order_shipping");
  1642. $order_shipping_tax = $db->f("order_shipping_tax");
  1643. $order_tax = $db->f("order_tax");
  1644. }
  1645. $order_total = $db->f("order_total");
  1646. $order_discount = $db->f("order_discount");
  1647. $coupon_discount = $db->f("coupon_discount");
  1648. // Email Addresses for shopper and vendor
  1649. // **************************************
  1650. $shopper_email = $dbbt->f("user_email");
  1651. $shopper_name = $dbbt->f("first_name")." ".$dbbt->f("last_name");
  1652. $from_email = $dbv->f("contact_email");
  1653. $shopper_subject = $dbv->f("vendor_name") . " ".($subject ? $subject : $VM_LANG->_('PHPSHOP_ORDER_PRINT_PO_LBL',false))." - " . $db->f("order_id");
  1654. $vendor_subject = $dbv->f("vendor_name") . " ".($subject ? $subject : $VM_LANG->_('PHPSHOP_ORDER_PRINT_PO_LBL',false))." - " . $db->f("order_id");
  1655. $shopper_order_link = str_replace('/administrator/','/',$sess->url( SECUREURL ."index.php?page=account.order_details&order_id=$order_id", true, false ));
  1656. $vendor_order_link = $sess->url( SECUREURL ."index2.php?page=order.order_print&order_id=$order_id&pshop_mode=admin", true, false );
  1657. /**
  1658. * Prepare the payment information, including Credit Card information when not empty
  1659. */
  1660. $payment_info_details = $db_payment->f("payment_method_name");
  1661. if( !empty( $_SESSION['ccdata']['order_payment_name'] )
  1662. && !empty($_SESSION['ccdata']['order_payment_number'])) {
  1663. $payment_info_details .= '<br />'.$VM_LANG->_('PHPSHOP_CHECKOUT_CONF_PAYINFO_NAMECARD',false).': '.$_SESSION['ccdata']['order_payment_name'].'<br />';
  1664. $payment_info_details .= $VM_LANG->_('PHPSHOP_CHECKOUT_CONF_PAYINFO_CCNUM',false).': '.$this->asterisk_pad($_SESSION['ccdata']['order_payment_number'], 4 ).'<br />';
  1665. $payment_info_details .= $VM_LANG->_('PHPSHOP_CHECKOUT_CONF_PAYINFO_EXDATE',false).': '.$_SESSION['ccdata']['order_payment_expire_month'].' / '.$_SESSION['ccdata']['order_payment_expire_year'].'<br />';
  1666. if( !empty($_SESSION['ccdata']['credit_card_code'])) {
  1667. $payment_info_details .= 'CVV code: '.$_SESSION['ccdata']['credit_card_code'].'<br />';
  1668. }
  1669. }
  1670. // Convert HTML into Text
  1671. $payment_info_details_text = str_replace( '<br />', "\n", $payment_info_details );
  1672. // Get the Shipping Details
  1673. $shipping_arr = explode("|", urldecode(vmGet($_REQUEST,"shipping_rate_id")) );
  1674. // Headers and Footers
  1675. // ******************************
  1676. // Shopper Header
  1677. $shopper_header = $VM_LANG->_('PHPSHOP_CHECKOUT_EMAIL_SHOPPER_HEADER1',false)."\n";
  1678. $legal_info_title = '';
  1679. $legal_info_html = '';
  1680. // Get the legal information about the returns/order cancellation policy
  1681. if( @VM_ONCHECKOUT_SHOW_LEGALINFO == '1' ) {
  1682. $article = intval(@VM_ONCHECKOUT_LEGALINFO_LINK);
  1683. if( $article > 0 ) {
  1684. $db_legal = new ps_DB();
  1685. // Get the content article, which contains the Legal Info
  1686. $db_legal->query( 'SELECT id, title, introtext FROM #__content WHERE id='.$article );
  1687. $db_legal->next_record();
  1688. if( $db_legal->f('introtext') ) {
  1689. $legal_info_title = $db_legal->f('title');
  1690. $legal_info_text = strip_tags( str_replace( '<br />', "\n", $db_legal->f('introtext') ));
  1691. $legal_info_html = $db_legal->f('introtext');
  1692. }
  1693. }
  1694. }
  1695. //Shopper Footer
  1696. $shopper_footer = "\n\n".$VM_LANG->_('PHPSHOP_CHECKOUT_EMAIL_SHOPPER_HEADER2',false)."\n";
  1697. if( VM_REGISTRATION_TYPE != 'NO_REGISTRATION' ) {
  1698. $shopper_footer .= "\n\n".$VM_LANG->_('PHPSHOP_CHECKOUT_EMAIL_SHOPPER_HEADER5',false)."\n";
  1699. $shopper_footer .= $shopper_order_link;
  1700. }
  1701. $shopper_footer .= "\n\n".$VM_LANG->_('PHPSHOP_CHECKOUT_EMAIL_SHOPPER_HEADER3',false)."\n";
  1702. $shopper_footer .= "Email: " . $from_email;
  1703. // New in version 1.0.5
  1704. if( @VM_ONCHECKOUT_SHOW_LEGALINFO == '1' && !empty( $legal_info_title )) {
  1705. $shopper_footer .= "\n\n____________________________________________\n";
  1706. $shopper_footer .= $legal_info_title."\n";
  1707. $shopper_footer .= $legal_info_text."\n";
  1708. }
  1709. // Vendor Header
  1710. switch( $db->f("order_status") ) {
  1711. case 'X' :
  1712. $vendor_header = $VM_LANG->_('PHPSHOP_CHECKOUT_EMAIL_SHOPPER_HEADER4a',false)."\n";
  1713. break;
  1714. default :
  1715. $vendor_header = $VM_LANG->_('PHPSHOP_CHECKOUT_EMAIL_SHOPPER_HEADER4',false)."\n";
  1716. break;
  1717. }
  1718. // Vendor Footer
  1719. $vendor_footer = "\n\n".$VM_LANG->_('PHPSHOP_CHECKOUT_EMAIL_SHOPPER_HEADER5',false)."\n";
  1720. $vendor_footer .= $vendor_order_link;
  1721. $vendor_email = $from_email;
  1722. /////////////////////////////////////
  1723. // set up text mail
  1724. //
  1725. // Main Email Message Purchase Order
  1726. // *********************************
  1727. $shopper_message = "\n".$VM_LANG->_('PHPSHOP_ORDER_PRINT_PO_LBL',false)."\n";
  1728. $shopper_message .= "------------------------------------------------------------------------\n";
  1729. $shopper_message .= $VM_LANG->_('PHPSHOP_ORDER_PRINT_PO_NUMBER',false).": " . $db->f("order_id") . "\n";
  1730. $shopper_message .= $VM_LANG->_('PHPSHOP_ORDER_PRINT_PO_DATE',false).": ";
  1731. $shopper_message .= strftime( $VM_LANG->_('DATE_FORMAT_LC'), $db->f("cdate") ) . "\n";
  1732. $shopper_message .= $VM_LANG->_('PHPSHOP_ORDER_PRINT_PO_STATUS',false).": ";
  1733. $shopper_message .= $order_status."\n\n";
  1734. // BillTo Fields
  1735. $registrationfields = ps_userfield::getUserFields('registration', false, '', false, true );
  1736. foreach( $registrationfields as $field ) {
  1737. if( $field->name == 'email') $field->name = 'user_email';
  1738. if( $field->name == 'delimiter_sendregistration' || $field->type == 'captcha') continue;
  1739. if( $field->type == 'delimiter') {
  1740. $shopper_message .= ($VM_LANG->_($field->title) != '' ? $VM_LANG->_($field->title) : $field->title)."\n";
  1741. $shopper_message .= "--------------------\n\n";
  1742. } else {
  1743. $shopper_message .= ($VM_LANG->_($field->title) != '' ? $VM_LANG->_($field->title) : $field->title).': ';
  1744. $shopper_message .= $dbst->f($field->name) . "\n";
  1745. }
  1746. }
  1747. // Shipping Fields
  1748. $shopper_message .= "\n\n";
  1749. $shopper_message .= $VM_LANG->_('PHPSHOP_ORDER_PRINT_SHIP_TO_LBL')."\n";
  1750. $shopper_message .= "-------\n\n";
  1751. $shippingfields = ps_userfield::getUserFields('shipping', false, '', false, true );
  1752. foreach( $shippingfields as $field ) {
  1753. if( $field->type == 'delimiter') {
  1754. $shopper_message .= ($VM_LANG->_($field->title) != '' ? $VM_LANG->_($field->title) : $field->title)."\n";
  1755. $shopper_message .= "--------------------\n\n";
  1756. } else {
  1757. $shopper_message .= ($VM_LANG->_($field->title) != '' ? $VM_LANG->_($field->title) : $field->title).': ';
  1758. $shopper_message .= $dbst->f($field->name) . "\n";
  1759. }
  1760. }
  1761. $shopper_message .= "\n\n";
  1762. $shopper_message .= $VM_LANG->_('PHPSHOP_ORDER_PRINT_ITEMS_LBL',false)."\n";
  1763. $shopper_message .= "-----------";
  1764. $sub_total = 0.00;
  1765. /** Organic Mod */
  1766. /** Gather the booking details for txt email */
  1767. $ps_booking->loadBookingData($order_id);
  1768. if($ps_booking->status) {
  1769. $oldmodulename = $modulename;
  1770. $modulename = 'booking';
  1771. $shopper_message .= "\n\n";
  1772. $shopper_message .= $VM_LANG->_('VM_BK_EMAIL_YOUR_BOOKING',false)." = ";
  1773. $shopper_message .= $ps_booking->property_data->name ."\n";
  1774. $shopper_message .= $VM_LANG->_('VM_BK_EMAIL_ARRIVE',false)." = ";
  1775. $shopper_message .= $ps_booking->dateFrom . "\n";
  1776. $shopper_message .= $VM_LANG->_('VM_BK_EMAIL_DEPART',false)." = ";
  1777. $shopper_message .= $ps_booking->dateTo . "\n";
  1778. $shopper_message .= $VM_LANG->_('VM_BK_EMAIL_NIGHTS',false)." = ";
  1779. $shopper_message .= $ps_booking->nights ."\n";
  1780. $shopper_message .= $VM_LANG->_('VM_BK_EMAIL_TOTAL',false)." = ";
  1781. if ($auth["show_price_including_tax"] == 1) {
  1782. $sub_total += $ps_booking->subtotal;
  1783. $shopper_message .= $CURRENCY_DISPLAY->getFullValue($ps_booking->subtotal, '', $db->f('order_currency'));
  1784. } else {
  1785. $sub_total += $ps_booking->subtotal;
  1786. $shopper_message .= $CURRENCY_DISPLAY->getFullValue($ps_booking->subtotal, '', $db->f('order_currency'));
  1787. }
  1788. $modulename = $oldmodulename;
  1789. }
  1790. while($dboi->next_record()) {
  1791. $shopper_message .= "\n\n";
  1792. $shopper_message .= $VM_LANG->_('PHPSHOP_PRODUCT',false)." = ";
  1793. if ($dboi->f("product_parent_id")) {
  1794. $shopper_message .= $dboi->f("order_item_name") . "\n";
  1795. $shopper_message .= "SERVICE = ";
  1796. }
  1797. $shopper_message .= $dboi->f("product_name") . "; ".$dboi->f("product_attribute") ."\n";
  1798. $shopper_message .= $VM_LANG->_('PHPSHOP_ORDER_PRINT_QUANTITY',false)." = ";
  1799. $shopper_message .= $dboi->f("product_quantity") . "\n";
  1800. $shopper_message .= $VM_LANG->_('PHPSHOP_ORDER_PRINT_SKU',false)." = ";
  1801. $shopper_message .= $dboi->f("order_item_sku") . "\n";
  1802. $shopper_message .= $VM_LANG->_('PHPSHOP_ORDER_PRINT_PRICE',false)." = ";
  1803. if ($auth["show_price_including_tax"] == 1) {
  1804. $sub_total += ($dboi->f("product_quantity") * $dboi->f("product_final_price"));
  1805. $shopper_message .= $CURRENCY_DISPLAY->getFullValue($dboi->f("product_final_price"), '', $db->f('order_currency'));
  1806. } else {
  1807. $sub_total += ($dboi->f("product_quantity") * $dboi->f("product_final_price"));
  1808. $shopper_message .= $CURRENCY_DISPLAY->getFullValue($dboi->f("product_item_price"), '', $db->f('order_currency'));
  1809. }
  1810. }
  1811. $shopper_message .= "\n\n";
  1812. $shopper_message .= $VM_LANG->_('PHPSHOP_ORDER_PRINT_SUBTOTAL',false)." = ";
  1813. $shopper_message .= $CURRENCY_DISPLAY->getFullValue($sub_total, '', $db->f('order_currency'))."\n";
  1814. if ( PAYMENT_DISCOUNT_BEFORE == '1') {
  1815. if( !empty($order_discount)) {
  1816. if ($order_discount > 0) {
  1817. $shopper_message .= $VM_LANG->_('PHPSHOP_PAYMENT_METHOD_LIST_DISCOUNT',false)." = ";
  1818. $shopper_message .= "- ".$CURRENCY_DISPLAY->getFullValue(abs($order_discount), '', $db->f('order_currency')) . "\n";
  1819. } else {
  1820. $shopper_message .= $VM_LANG->_('PHPSHOP_FEE',false)." = ";
  1821. $shopper_message .= "+ ".$CURRENCY_DISPLAY->getFullValue(abs($order_discount), '', $db->f('order_currency')) . "\n";
  1822. }
  1823. }
  1824. if( !empty($coupon_discount)) {
  1825. /* following 2 lines added by Erich for coupon hack */
  1826. $shopper_message .= $VM_LANG->_('PHPSHOP_COUPON_DISCOUNT',false) . ": ";
  1827. $shopper_message .= $CURRENCY_DISPLAY->getFullValue($coupon_discount, '', $db->f('order_currency')) . "\n";
  1828. }
  1829. }
  1830. if ($auth["show_price_including_tax"] != 1) {
  1831. $shopper_message .= $VM_LANG->_('PHPSHOP_ORDER_PRINT_TOTAL_TAX',false)." = ";
  1832. $shopper_message .= $CURRENCY_DISPLAY->getFullValue($order_tax, '', $db->f('order_currency')) . "\n";
  1833. }
  1834. $shopper_message .= $VM_LANG->_('PHPSHOP_ORDER_PRINT_SHIPPING',false)." = ";
  1835. $shopper_message .= $CURRENCY_DISPLAY->getFullValue($order_shipping, '', $db->f('order_currency')) . "\n";
  1836. if( !empty($order_shipping_tax)) {
  1837. $shopper_message .= $VM_LANG->_('PHPSHOP_ORDER_PRINT_SHIPPING_TAX',false)." = ";
  1838. $shopper_message .= $CURRENCY_DISPLAY->getFullValue($order_shipping_tax, '', $db->f('order_currency'));
  1839. }
  1840. $shopper_message .= "\n\n";
  1841. if ( PAYMENT_DISCOUNT_BEFORE != '1') {
  1842. if( !empty($order_discount)) {
  1843. if ($order_discount > 0) {
  1844. $shopper_message .= $VM_LANG->_('PHPSHOP_PAYMENT_METHOD_LIST_DISCOUNT',false)." = ";
  1845. $shopper_message .= "- ".$CURRENCY_DISPLAY->getFullValue(abs($order_discount), '', $db->f('order_currency')) . "\n";
  1846. } else {
  1847. $shopper_message .= $VM_LANG->_('PHPSHOP_FEE',false)." = ";
  1848. $shopper_message .= "+ ".$CURRENCY_DISPLAY->getFullValue(abs($order_discount), '', $db->f('order_currency')) . "\n";
  1849. }
  1850. }
  1851. if( !empty($coupon_discount)) {
  1852. /* following 2 lines added by Erich for coupon hack */
  1853. $shopper_message .= $VM_LANG->_('PHPSHOP_COUPON_DISCOUNT',false) . ": ";
  1854. $shopper_message .= $CURRENCY_DISPLAY->getFullValue($coupon_discount, '', $db->f('order_currency')) . "\n";
  1855. }
  1856. }
  1857. $shopper_message .= $VM_LANG->_('PHPSHOP_ORDER_PRINT_TOTAL',false)." = ";
  1858. $shopper_message .= $CURRENCY_DISPLAY->getFullValue($order_total, '', $db->f('order_currency'));
  1859. if ($auth["show_price_including_tax"] == 1) {
  1860. $shopper_message .= "\n---------------";
  1861. $shopper_message .= "\n";
  1862. $shopper_message .= $VM_LANG->_('PHPSHOP_ORDER_PRINT_TOTAL_TAX',false)." = ";
  1863. $shopper_message .= $CURRENCY_DISPLAY->getFullValue($order_tax, '', $db->f('order_currency')) . "\n";
  1864. }
  1865. if( $db->f('order_tax_details') ) {
  1866. $shopper_message .= str_replace( '<br />', "\n", ps_checkout::show_tax_details( $db->f('order_tax_details'), $db->f('order_currency') ));
  1867. }
  1868. // Payment Details
  1869. $shopper_message .= "\n\n------------------------------------------------------------------------\n";
  1870. $shopper_message .= $payment_info_details_text;
  1871. // Shipping Details
  1872. if( is_object($this->_SHIPPING) ) {
  1873. $shopper_message .= "\n\n------------------------------------------------------------------------\n";
  1874. $shopper_message .= $VM_LANG->_('PHPSHOP_ORDER_PRINT_SHIPPING_LBL',false).":\n";
  1875. $shopper_message .= $shipping_arr[1]." (".$shipping_arr[2].")";
  1876. }
  1877. // Customer Note
  1878. $shopper_message .= "\n\n------------------------------------------------------------------------\n";
  1879. $shopper_message .= "\n".$VM_LANG->_('PHPSHOP_ORDER_PRINT_CUSTOMER_NOTE',false)."\n";
  1880. $shopper_message .= "---------------";
  1881. $shopper_message .= "\n";
  1882. if( !empty( $customer_note )) {
  1883. $shopper_message .= $customer_note."\n";
  1884. }
  1885. else {
  1886. $shopper_message .= " ./. \n";
  1887. }
  1888. $shopper_message .= "------------------------------------------------------------------------\n";
  1889. // Decode things like &euro; => €
  1890. $shopper_message = vmHtmlEntityDecode( $shopper_message );
  1891. // End of Purchase Order
  1892. // *********************
  1893. /**
  1894. * Setup the notification settings
  1895. */
  1896. if((@VB_NOTIFY_ADD_CUST && $modulename == 'checkout')){
  1897. $email_customer = 1;
  1898. }
  1899. if((@VB_NOTIFY_ADD_OWNER && $modulename == 'checkout')){
  1900. $email_owner = 1;
  1901. }
  1902. if((@VB_NOTIFY_ADD_ADMIN && $modulename == 'checkout')){
  1903. $email_vendor = 1;
  1904. }
  1905. //
  1906. //END: set up text mail
  1907. /////////////////////////////////////
  1908. // Send text email
  1909. //
  1910. if (ORDER_MAIL_HTML == '0') {
  1911. $msg = $shopper_header . $shopper_message . $shopper_footer;
  1912. if($email_customer || $hasPaid){
  1913. // Mail receipt to the shopper
  1914. vmMail( $from_email, $mosConfig_fromname, $shopper_email, $shopper_subject, $msg, "" );
  1915. }
  1916. $msg = $vendor_header . $shopper_message . $vendor_footer;
  1917. $owner = $ps_booking->getOwner();
  1918. if(($email_owner || $hasPaid) && $owner->f('email')){
  1919. // Mail receipt for owner
  1920. vmMail($from_email, $mosConfig_fromname, $owner->f('email'), $vendor_subject, $msg, "" );
  1921. }
  1922. if($email_vendor || $hasPaid){
  1923. // Mail receipt to the vendor
  1924. vmMail($from_email, $mosConfig_fromname, $vendor_email, $vendor_subject, $msg, "" );
  1925. }
  1926. }
  1927. ////////////////////////////
  1928. // set up the HTML email
  1929. //
  1930. elseif (ORDER_MAIL_HTML == '1') {
  1931. $dboi->query($q_oi);
  1932. // Create Template Object
  1933. $template = vmTemplate::getInstance();
  1934. if ($order_discount > 0) {
  1935. $order_discount_lbl = $VM_LANG->_('PHPSHOP_PAYMENT_METHOD_LIST_DISCOUNT');
  1936. $order_discount_plusminus = '-';
  1937. } else {
  1938. $order_discount_lbl = $VM_LANG->_('PHPSHOP_FEE');
  1939. $order_discount_plusminus = '+';
  1940. }
  1941. if ($coupon_discount > 0) {
  1942. $coupon_discount_lbl = $VM_LANG->_('PHPSHOP_PAYMENT_METHOD_LIST_DISCOUNT');
  1943. $coupon_discount_plusminus = '-';
  1944. } else {
  1945. $coupon_discount_lbl = $VM_LANG->_('PHPSHOP_FEE');
  1946. $coupon_discount_plusminus = '+';
  1947. }
  1948. if( is_object($this->_SHIPPING) ) {
  1949. $shipping_info_details = stripslashes($shipping_arr[1])." (".stripslashes($shipping_arr[2]).")";
  1950. }
  1951. else {
  1952. $shipping_info_details = ' ./. ';
  1953. }
  1954. //Load the booking language file
  1955. $GLOBALS['VM_LANG']->load('booking');
  1956. // These are a lot of vars to import for the email confirmation
  1957. $template->set_vars(array(
  1958. 'is_email_to_shopper' => true,
  1959. 'db' => $db,
  1960. 'dboi' => $dboi,
  1961. 'dbbt' => $dbbt,
  1962. 'dbst' => $dbst,
  1963. 'ps_booking' => $ps_booking, # Pass booking details
  1964. 'ps_product' => $ps_product,
  1965. 'shippingfields' => $shippingfields,
  1966. 'registrationfields' => $registrationfields,
  1967. 'order_id' => $order_id,
  1968. 'order_discount' => $order_discount,
  1969. 'order_discount_lbl' => $order_discount_lbl,
  1970. 'order_discount_plusminus' => $order_discount_plusminus,
  1971. 'coupon_discount' => $coupon_discount,
  1972. 'coupon_discount_lbl' => $coupon_discount_lbl,
  1973. 'coupon_discount_plusminus' => $coupon_discount_plusminus,
  1974. 'order_date' => $VM_LANG->convert( vmFormatDate($db->f("cdate"), $VM_LANG->_('DATE_FORMAT_LC') )),
  1975. 'order_status' => $order_status,
  1976. 'legal_info_title' => $legal_info_title,
  1977. 'legal_info_html' => $legal_info_html,
  1978. 'order_link' => $shopper_order_link,
  1979. 'payment_info_lbl' => $VM_LANG->_('PHPSHOP_ORDER_PRINT_PAYINFO_LBL'),
  1980. 'payment_info_details' => $payment_info_details,
  1981. 'shipping_info_lbl' => $VM_LANG->_('PHPSHOP_ORDER_PRINT_SHIPPING_LBL'),
  1982. 'shipping_info_details' => $shipping_info_details,
  1983. 'from_email' => $from_email,
  1984. 'customer_note' => nl2br($customer_note),
  1985. 'order_header_msg' => $shopper_header,
  1986. 'order_subtotal' => $CURRENCY_DISPLAY->getFullValue($sub_total, '', $db->f('order_currency')),
  1987. 'order_shipping' => $CURRENCY_DISPLAY->getFullValue($order_shipping, '', $db->f('order_currency')),
  1988. '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') ),
  1989. 'order_total' => $CURRENCY_DISPLAY->getFullValue($order_total, '', $db->f('order_currency')),
  1990. ));
  1991. $shopper_html = $template->fetch('order_emails/confirmation_email.tpl.php');
  1992. // Reset the list of order items for use in the vendor email
  1993. $dboi->reset();
  1994. // Override some vars for the vendor email, so we can use the same template
  1995. $template->set_vars(array(
  1996. 'order_header_msg' => $vendor_header,
  1997. 'order_link' => $vendor_order_link,
  1998. 'is_email_to_shopper' => false
  1999. ));
  2000. $vendor_html = $template->fetch('order_emails/confirmation_email.tpl.php');
  2001. /*
  2002. * Add the text, html and embedded images.
  2003. * The name of the image should match exactly
  2004. * (case-sensitive) to the name in the html.
  2005. */
  2006. $shopper_mail_Body = $shopper_html;
  2007. $shopper_mail_AltBody = $shopper_header . $shopper_message . $shopper_footer;
  2008. $vendor_mail_Body = $vendor_html;
  2009. $vendor_mail_AltBody = $vendor_header . $shopper_message . $vendor_footer;
  2010. $imagefile = pathinfo($dbv->f("vendor_full_image"));
  2011. $extension = $imagefile['extension'] == "jpg" ? "jpeg" : "jpeg";
  2012. $EmbeddedImages[] = array( 'path' => IMAGEPATH."vendor/".$dbv->f("vendor_full_image"),
  2013. 'name' => "vendor_image",
  2014. 'filename' => $dbv->f("vendor_full_image"),
  2015. 'encoding' => "base64",
  2016. 'mimetype' => "image/".$extension );
  2017. /* if($order_id == 12945){
  2018. $shopper_email = 'phil.c@organic-development.com';
  2019. echo $shopper_html;
  2020. exit();
  2021. }
  2022. */
  2023. # Mail customer
  2024. if($email_customer || $hasPaid){
  2025. $shopper_mail = vmMail( $from_email, $mosConfig_fromname, $shopper_email, $shopper_subject, $shopper_mail_Body, $shopper_mail_AltBody, true, null, null, $EmbeddedImages);
  2026. }else{
  2027. $shopper_mail = 1;
  2028. }
  2029. # Mail vendor
  2030. if($email_vendor || $hasPaid){
  2031. $vendor_mail = vmMail( $shopper_email, $shopper_name, $vendor_email, $vendor_subject, $vendor_mail_Body, $vendor_mail_AltBody, true, null, null, $EmbeddedImages);
  2032. }else{
  2033. $vendor_mail = 1;
  2034. }
  2035. # Mail vendor
  2036. $owner = $ps_booking->getOwner();
  2037. if(($email_owner || $hasPaid) && $owner->f('email')){
  2038. vmMail( $from_email, $shopper_name, $owner->f('email'), $vendor_subject, $vendor_mail_Body, $vendor_mail_AltBody, true, null, null, $EmbeddedImages);
  2039. }
  2040. if ( !$shopper_mail || !$vendor_mail ) {
  2041. $vmLogger->debug( 'Something went wrong while sending the order confirmation email to '.$from_email.' and '.$shopper_email );
  2042. return false;
  2043. }
  2044. //
  2045. // END: set up and send the HTML email
  2046. ////////////////////////////////////////
  2047. }
  2048. return true;
  2049. } // end of function email_receipt()
  2050. /**
  2051. * Return $str with all but $display_length at the end as asterisks.
  2052. * @author gday
  2053. *
  2054. * @param string $str The string to mask
  2055. * @param int $display_length The length at the end of the string that is NOT masked
  2056. * @param boolean $reversed When true, masks the end. Masks from the beginning at default
  2057. * @return string The string masked by asteriks
  2058. */
  2059. function asterisk_pad($str, $display_length, $reversed = false) {
  2060. $total_length = strlen($str);
  2061. if($total_length > $display_length) {
  2062. if( !$reversed) {
  2063. for($i = 0; $i < $total_length - $display_length; $i++) {
  2064. $str[$i] = "*";
  2065. }
  2066. }
  2067. else {
  2068. for($i = $total_length-1; $i >= $total_length - $display_length; $i--) {
  2069. $str[$i] = "*";
  2070. }
  2071. }
  2072. }
  2073. return($str);
  2074. }
  2075. /**
  2076. * Displays the order_tax_details array when it contains
  2077. * more than one
  2078. * @param mixed $details
  2079. * @return string
  2080. */
  2081. function show_tax_details( $details, $currency = '' ) {
  2082. global $discount_factor, $CURRENCY_DISPLAY, $VM_LANG;
  2083. if( !isset( $discount_factor) || !empty($_REQUEST['discount_factor'])) {
  2084. $discount_factor = 1;
  2085. }
  2086. $auth = $_SESSION['auth'];
  2087. if( !is_array( $details )) {
  2088. $details = @unserialize( $details );
  2089. if( !is_array($details)) {
  2090. return false;
  2091. }
  2092. }
  2093. $html = '';
  2094. if( sizeof( $details) > 1 ) {
  2095. $html .= '<br />'.$VM_LANG->_('VM_TAXDETAILS_LABEL').':<br />';
  2096. foreach ($details as $rate => $value ) {
  2097. if( !$auth['show_price_including_tax']) {
  2098. $value /= $discount_factor;
  2099. }
  2100. $rate = str_replace( '-', $CURRENCY_DISPLAY->decimal, $rate )*100;
  2101. $html .= $CURRENCY_DISPLAY->getFullValue( $value, 5, $currency ).' ('.$rate.'% '.$VM_LANG->_('PHPSHOP_CART_TAX').')<br />';
  2102. }
  2103. }
  2104. return $html;
  2105. }
  2106. /*
  2107. * @abstract This function is very useful to round totals with definite decimals.
  2108. *
  2109. * @param float $value
  2110. * @param integer $dec
  2111. * @return float
  2112. */
  2113. function approx( $value, $dec = 2 ) {
  2114. $value += 0.0;
  2115. $unit = floor( $value * pow( 10, $dec + 1 ) ) / 10;
  2116. $round = round( $unit );
  2117. return $round / pow( 10, $dec );
  2118. }
  2119. /**
  2120. * If the customer is in the EU then tax should be charged according to the
  2121. * vendor's address, and this function will return true.
  2122. */
  2123. function tax_based_on_vendor_address () {
  2124. global $__tax_based_on_vendor_address;
  2125. global $vmLogger;
  2126. if (!isset ($__tax_based_on_vendor_address)) {
  2127. $__tax_based_on_vendor_address = ps_checkout::_tax_based_on_vendor_address ();
  2128. if ($__tax_based_on_vendor_address)
  2129. $vmLogger->debug ('calculating tax based on vendor address');
  2130. else
  2131. $vmLogger->debug ('calculating tax based on shipping address');
  2132. }
  2133. return $__tax_based_on_vendor_address;
  2134. }
  2135. function _tax_based_on_vendor_address () {
  2136. global $auth;
  2137. global $vmLogger;
  2138. switch (TAX_MODE) {
  2139. case '0':
  2140. return false;
  2141. case '1':
  2142. return true;
  2143. case '17749':
  2144. if (! array_key_exists ('country', $auth)) {
  2145. $vmLogger->debug ('shopper\'s country is not known; defaulting to vendor-based tax');
  2146. return true;
  2147. }
  2148. $vmLogger->debug ('shopper is in ' . $auth['country']);
  2149. return ps_checkout::country_in_eu_common_vat_zone ($auth['country']);
  2150. default:
  2151. $vmLogger->warning ('unknown TAX_MODE "' . TAX_MODE . '"');
  2152. return true;
  2153. }
  2154. }
  2155. function country_in_eu_common_vat_zone ($country) {
  2156. $eu_countries = array ('AUT', 'BGR', 'BEL', 'CYP', 'CZE', 'DEU', 'DNK', 'ESP', 'EST',
  2157. 'FIN', 'FRA', 'FXX', 'GBR', 'GRC', 'HUN', 'IRL', 'ITA', 'LVA', 'LTU',
  2158. 'LUX', 'MLT', 'NLD', 'POL', 'PRT', 'ROM', 'SVK', 'SVN', 'SWE');
  2159. return in_array ($country, $eu_countries);
  2160. }
  2161. }
  2162. ?>