cartData['couponCode'] */ var $couponCode = ''; var $order_language = ''; var $orderDetails = 0; var $totalProduct = 0; var $productsQuantity = array(); var $lists = null; var $order_number=null; // added to solve emptying cart for payment notification var $order_pass=null; var $virtuemart_order_id = false; var $OrderIdOrderDone = false; var $customer_number=null; var $cartAdv = false; var $pricesCurrency = null; var $paymentCurrency = null; var $STsameAsBT = 1; var $selected_shipto = 0; var $productParentOrderable = TRUE; var $_triesValidateCoupon = array(); var $cartProductsData = array(); var $cartData = array(); var $cartPrices = array(); var $layout ; var $layoutPath=''; var $orderdoneHtml = false; var $virtuemart_cart_id = 0; var $customer_notified = false; /* @deprecated */ var $pricesUnformatted = array(); private static $_cart = null; static $_carts = null; var $tempCart = false; var $useXHTML = false; var $useSSL = 1; var $storeCartSession = true; var $productCartLoaded = array(); var $loadedCart = false; var $user = null; var $_guest = true; public function __construct() { $this->useSSL = vmURI::useSSL(); $this->useXHTML = false; $this->cartProductsData = array(); $this->layout = VmConfig::get('cartlayout','default'); $this->_confirmDone = false; if(empty($this->layout)){ $this->layout = 'default'; } } private static $lastVendorId = 1; public static $_session = null; /** * Get the cart from the session * * @author Max Milbers * @access public * @param array $cart the cart to store in the session */ public static function &getCart($forceNew=false, $options = array(), $cartData=NULL, $vendorId = NULL) { $multixcart = VmConfig::get('multixcart',0); self::$_session = JFactory::getSession($options); if(empty($multixcart)){ $vendorId = 1; //vmdebug('No Multicart vendorId = 1'); } else { if($vendorId === NULL){ $lastVendorId = self::$_session->get('vmcartlastVendorId', 0, 'vm'); if($lastVendorId!=0){ $vendorId = $lastVendorId; //vmdebug('getCart use lastVendorId',$lastVendorId); } if($multixcart=='byvendor' /*or self::$_cart->vendorId==1*/){ $vId = vmAccess::isSuperVendor(); if(!empty($vId) and $vId!=1){ $vendorId = $vId; } } if($multixcart=='byselection' or $multixcart=='byproduct'){ $tmpVendId = vRequest::getInt('virtuemart_vendor_id',false); if($tmpVendId!=false){ $vendorId = $tmpVendId; } } if(empty($vendorId)) $vendorId = 1; //vmdebug('getCart Multicart vendorId '.$multixcart,$vendorId); } } if(empty(self::$_carts[$vendorId]) or $forceNew){ self::$_cart = new VirtueMartCart; self::$_cart->vendorId = $vendorId; if (empty($cartData)) { if($multixcart!='byproduct'){ $sessionCart = self::$_session->get('vmcart', 0, 'vm'); } else { $sessionCart = self::$_session->get('vmcarts.'.$vendorId, 0, 'vm'); } if (!empty($sessionCart)) { $sessionCart = (object)vmJsApi::safe_json_decode( $sessionCart ,true); } } else { $sessionCart=$cartData; } $userModel = VmModel::getModel('user'); self::$_cart->user = $userModel->getCurrentUser(); $lang = vmLanguage::getLanguage(); self::$_cart->order_language = $lang->getTag(); self::$_cart->_guest = true; self::$_cart->loadedCart = false; $setInSession = false; if (!empty($sessionCart)) { if(isset($sessionCart->cartProductsData)){ self::$_cart->cartProductsData = $sessionCart->cartProductsData; self::$_cart->lastVisitedCategoryId = $sessionCart->lastVisitedCategoryId; self::$_cart->virtuemart_shipmentmethod_id = $sessionCart->virtuemart_shipmentmethod_id; self::$_cart->virtuemart_paymentmethod_id = $sessionCart->virtuemart_paymentmethod_id; self::$_cart->automaticSelectedShipment = $sessionCart->automaticSelectedShipment; self::$_cart->automaticSelectedPayment = $sessionCart->automaticSelectedPayment; self::$_cart->BT = $sessionCart->BT; self::$_cart->ST = $sessionCart->ST; self::$_cart->cartfields = $sessionCart->cartfields; self::$_cart->couponCode = $sessionCart->couponCode; self::$_cart->_triesValidateCoupon = $sessionCart->_triesValidateCoupon; self::$_cart->order_number = $sessionCart->order_number; self::$_cart->pricesCurrency = $sessionCart->pricesCurrency; self::$_cart->paymentCurrency = $sessionCart->paymentCurrency; self::$_cart->_guest = $sessionCart->_guest; self::$_cart->_inCheckOut = $sessionCart->_inCheckOut; self::$_cart->_inConfirm = $sessionCart->_inConfirm; self::$_cart->_redirected = $sessionCart->_redirected; self::$_cart->_dataValidated = $sessionCart->_dataValidated; //self::$_cart->_confirmDone = $sessionCart->_confirmDone; self::$_cart->STsameAsBT = $sessionCart->STsameAsBT; self::$_cart->selected_shipto = $sessionCart->selected_shipto; self::$_cart->_fromCart = $sessionCart->_fromCart; self::$_cart->layout = $sessionCart->layout; self::$_cart->layoutPath = $sessionCart->layoutPath; self::$_cart->virtuemart_cart_id = $sessionCart->virtuemart_cart_id; self::$_cart->OrderIdOrderDone = isset($sessionCart->OrderIdOrderDone)? $sessionCart->OrderIdOrderDone:false; self::$_cart->orderdoneHtml = $sessionCart->orderdoneHtml; self::$_cart->virtuemart_order_id = $sessionCart->virtuemart_order_id; self::$_cart->byDefaultBT = isset($sessionCart->byDefaultBT)? $sessionCart->byDefaultBT: array(); self::$_cart->byDefaultST = isset($sessionCart->byDefaultST)? $sessionCart->byDefaultST: array(); self::$_cart->lastAddedProduct = isset($sessionCart->lastAddedProduct)? $sessionCart->lastAddedProduct: 0; } self::$_cart->_guest = isset($sessionCart->_guest)? $sessionCart->_guest: true; self::$_cart->productCartLoaded = isset($sessionCart->productCartLoaded)? $sessionCart->productCartLoaded: array(); self::$_cart->loadedCart = isset($sessionCart->loadedCart)? $sessionCart->loadedCart: false; } else { $setInSession = true; } if((int)self::$_cart->_guest!=(int)self::$_cart->user->JUser->guest){ self::$_cart->loadedCart = false; } if(VmConfig::isSite() and empty(self::$_cart->loadedCart) ){ self::$_cart->loadCart(self::$_cart); } //self::$_cart->selected_shipto = vRequest::getVar('shipto', self::$_cart->selected_shipto); if(empty(self::$_cart->selected_shipto)){ //self::$_cart->STsameAsBT = 1; } self::$_cart->setupAddressFieldsForCart(true, true); if (empty(self::$_cart->virtuemart_shipmentmethod_id) && !empty(self::$_cart->user->virtuemart_shipmentmethod_id)) { self::$_cart->virtuemart_shipmentmethod_id = self::$_cart->user->virtuemart_shipmentmethod_id; } if (empty(self::$_cart->virtuemart_paymentmethod_id) && !empty(self::$_cart->user->virtuemart_paymentmethod_id)) { self::$_cart->virtuemart_paymentmethod_id = self::$_cart->user->virtuemart_paymentmethod_id; } if((!empty(self::$_cart->user->tos) || !empty(self::$_cart->BT['tos'])) && !VmConfig::get('agree_to_tos_onorder',0) ){ self::$_cart->BT['tos'] = 1; } if(!empty(self::$_cart->user->customer_number)){ self::$_cart->customer_number = self::$_cart->user->customer_number; } if(empty(self::$_cart->customer_number) or strpos(self::$_cart->customer_number,'nonreg_')!==FALSE){ $firstName = empty(self::$_cart->BT['first_name'])? '':self::$_cart->BT['first_name']; $lastName = empty(self::$_cart->BT['last_name'])? '':self::$_cart->BT['last_name']; $email = empty(self::$_cart->BT['email'])? '':self::$_cart->BT['email']; $qdate = date("Ymd_His_"); self::$_cart->customer_number = 'nonreg_'.shopFunctionsF::vmSubstr($firstName,0,2).shopFunctionsF::vmSubstr($lastName,0,2).shopFunctionsF::vmSubstr($email,0,2).$qdate; } //We need to check for the amount of products. A cart in Multix mode using the first product // to determine the vendorId is a valid if there is no product in the cart $cp = count(self::$_cart->cartProductsData); if( $cp >0 and empty(self::$_cart->vendorId)){ self::$_cart->vendorId = 1; } self::$_session->set('vmcartlastVendorId', $vendorId, 'vm'); self::$lastVendorId = $vendorId; if($setInSession){ self::$_cart->setCartIntoSession(); } self::$_carts[self::$_cart->vendorId] = &self::$_cart; } else { self::$_session->set('vmcartlastVendorId', $vendorId, 'vm'); self::$_cart = self::$_carts[$vendorId]; } return self::$_cart; } function setupAddressFieldsForCart($update = false, $onlyDefaults = false){ if($this->BT==0) $this->BT = array(); if($this->ST==0) $this->ST = array(); if($this->cartfields==0) $this->cartfields = array(); //vmdebug('setupAddressFieldsForCart the begin ',$this->STsameAsBT,$this->BT,$this->ST,$this->cartfields); $bt = $this->BT; $st = $this->ST; $default['BT']=true; $default['ST']=true; $btloaded = false; $stloaded = false; //If the user is logged in and exists, we check if he has already addresses stored if(!empty($this->user->virtuemart_user_id)){ //quorvia load stored shopper addresses regardless what is in cart if(VmConfig::get( 'alwaysLoadStoredShopperAddress', 0 )) { foreach( $this->user->userInfo as $address ) { if($address->address_type == 'BT') { $this->saveAddressInCart( (array)$address, $address->address_type, FALSE ); } else { if(!empty( $this->selected_shipto ) and $address->virtuemart_userinfo_id == $this->selected_shipto) { $this->saveAddressInCart( (array)$address, $address->address_type, FALSE, '' ); } } } } $loadBT = true; $countBT = count($this->BT) - count($this->cartfields); //vmdebug('my setupAddressFieldsForCart $countBT $this->byDefaultBT',(int)$countBT, (int) count($this->byDefaultBT)); //Check if the address is already loaded if( $countBT > count($this->byDefaultBT) ){ $loadBT = false; } $loadST = true; $selected_shipto = vRequest::getVar('shipto', $this->selected_shipto); if( $selected_shipto==$this->selected_shipto and count($this->ST) > count($this->byDefaultST) ){ $loadST = false; } $this->selected_shipto = $selected_shipto; //vmdebug('my $loadBT $loadST',(int)$loadBT, (int) $loadST); foreach ($this->user->userInfo as $address) { if ($loadBT and $address->address_type == 'BT') { $bt = $address->loadFieldValues(); $btloaded = true; } else if($loadST and !empty($this->selected_shipto) and $address->virtuemart_userinfo_id==$this->selected_shipto){ //$this->saveAddressInCart((array) $address, $address->address_type,false,''); $st = $address->loadFieldValues(); $stloaded = true; $this->STsameAsBT = 0; $this->ST = array(); // vmdebug('setupAddressFieldsForCart found stored ST ',$st); } } if(empty($this->selected_shipto)){ $this->STsameAsBT = 1; $this->ST = array(); } else { $this->STsameAsBT = 0; } } $userFieldsModel = VmModel::getModel('Userfields'); $types = array('BT','ST'); foreach($types as $type){ if($type=='ST'){ $preFix = 'shipto_'; if($stloaded){ $defaults = $this->byDefaultST; if(!empty($defaults)){ foreach($defaults as $name=>$v){ if(isset($this->{$type}[$name])){ $this->{$type}[$name] = ''; } } } $data = $this->ST = self::mergeArraysOverrideEmpty($st, $this->ST); } else { $data = $this->ST; } } else { $preFix = ''; if($btloaded){ $defaults = $this->byDefaultBT; if(!empty($defaults)){ foreach($defaults as $name=>$v){ if(isset($this->{$type}[$name])){ $this->{$type}[$name] = ''; } } } $data = $this->BT = self::mergeArraysOverrideEmpty($bt, $this->BT); } else { $data = $this->BT; } } $addresstype = $type.'address'; //for example BTaddress if($update or empty($this->{$addresstype})){ $userFields = $userFieldsModel->getUserFieldsFor('cart',$type); $this->{$addresstype} = $userFieldsModel->getUserFieldsFilled( $userFields ,$data ,$preFix ,$onlyDefaults ); if(!empty($this->{$addresstype}['byDefault'])){ if($type=='BT'){ $this->byDefaultBT = $this->{$addresstype}['byDefault']; } else { $this->byDefaultST = $this->{$addresstype}['byDefault']; } } if(!empty($this->{$addresstype}['fields'])){ $this->bindUserfieldToCart($type, $this->{$addresstype}['fields']); } else { vmdebug('cart helper found no userfields to bind'); } } } } public function unsetDefaults($type, $ar){ if($type == 'BT'){ $defaults = $this->byDefaultBT; } else { $defaults = $this->byDefaultST; } vmdebug('unsetDefaults $defaults',$defaults); if(!empty($defaults)){ foreach($defaults as $name=>$v){ if(isset($ar[$name])){ unset($ar[$name]); } } } if($type == 'BT'){ $this->byDefaultBT = array(); } else { $this->byDefaultST = array(); } vmdebug('Defaults UNSET '.$type,$ar); return $ar; } static public function mergeArraysOverrideEmpty($ar1, $ar2){ //vmdebug('mergeArraysOverrideEmpty Going to merge,',$ar1, $ar2); $arr = array_merge($ar1, $ar2); foreach($arr as $n =>$v){ if(empty($v) and !empty($ar1[$n])) $arr[$n] = $ar1[$n]; } //vmdebug('mergeArraysOverrideEmpty result',$arr); return $arr; } public $byDefaultBT = array(); public $byDefaultST = array(); private function bindUserfieldToCart($type, $userFields){ //vmdebug('bindUserfieldToCart type before bind '.$type,$this->{$type}); foreach ($userFields as $name=>$fld) { if(!empty($fld['name'])){ if(empty($this->{$type}[$name]) or !empty($userFields['byDefault'][$name])){ if($name=='virtuemart_country_id' and !empty( $fld['virtuemart_country_id'])){ $this->{$type}[$name] = $fld['virtuemart_country_id']; } else if ($name=='virtuemart_state_id' and !empty( $fld['virtuemart_state_id'])){ $this->{$type}[$name] = $fld['virtuemart_state_id']; } else if(!empty( $fld['value'])) { $this->{$type}[$name] = $fld['value']; } } } } //vmdebug('bindUserfieldToCart type AFTER bind '.$type,$this->{$type}); } /** * @deprecated use setupAddressFieldsForCart instead */ function loadSetRenderBTSTAddress(){ //If the user is logged in and exists, we check if he has already addresses stored if(!empty($this->user->virtuemart_user_id)){ foreach ($this->user->userInfo as $address) { if ($address->address_type == 'BT') { $this->saveAddressInCart((array) $address, $address->address_type,false); } else { if(!empty($this->selected_shipto) and $address->virtuemart_userinfo_id==$this->selected_shipto){ $this->saveAddressInCart((array) $address, $address->address_type,false,''); } } } if(empty($this->selected_shipto)){ $this->STsameAsBT = 1; $this->ST = 0; } } } /** * @deprecated use setupAddressFieldsForCart instead */ //function prepareAddressDataInCart($type='BT',$new = false,$virtuemart_user_id = null){ function prepareAddressFieldsInCart($update=false){ $userFieldsModel = VmModel::getModel('Userfields'); $types = array('BT','ST'); foreach($types as $type){ if($type=='ST'){ $preFix = 'shipto_'; } else { $preFix = ''; } $addresstype = $type.'address'; //for example BTaddress if($update or empty($this->{$addresstype})){ $userFields = $userFieldsModel->getUserFieldsFor('cart',$type); $this->{$addresstype} = $userFieldsModel->getUserFieldsFilled( $userFields ,$this->{$type} ,$preFix ); $this->bindUserfieldToCart($type, $this->{$addresstype}['fields']); vmdebug('prepareAddressFieldsInCart '.$addresstype,$this->{$type}); } } } var $storeToDB = false; /** * Loads cart from the cart table * @author Max Milbers */ public function loadCart(&$existingSession){ /*stAn - set this to true to not merge cart if current cart is not empty - useful if your login page is after your cart content page*/ $enableCartMerging = VmConfig::get('enableCartMerging', true); /*stAn - this is a global disabler - either per plugins setting this temporary during the process or generally - disables both cookie and DB cart load */ $cartLoad = VmConfig::get('enableCartLoad', true); if (empty($cartLoad)) { return; } if (empty($enableCartMerging) && (!empty($existingSession->cartProductsData))) { return; } $currentUser = JFactory::getUser(); if(!empty($existingSession->loadedCart)){ return false; } else { if($existingSession){ //vmdebug('Executing loadCart set $existingSession->loadedCart = true'); $this->loadedCart = true; $this->storeToDB = true; } } //vmdebug('Executing loadCart '); if( $currentUser->guest ){ if(empty(VmConfig::get('cartCookieExpire',0))){ return false; } else { $cookie = JFactory::getApplication()->input->cookie; $cartData = $cookie->get('myCart', null, $filter = 'string'); if(empty($cartData)){ vmdebug('loadCart, there is no CookieData ', $_COOKIE); return; } else { vmdebug('loadCart, CookieData loaded '); $cartData = vmJsApi::safe_json_decode(urldecode($cartData),true); } } } else { $model = new VmModel(); $carts = $model->getTable('carts'); if(!empty($existingSession->virtuemart_cart_id)){ $carts->load($existingSession->virtuemart_cart_id,'virtuemart_cart_id'); } else { $carts->load($currentUser->id,0,' ORDER BY `modified_on` DESC'); } $cartData = $carts->loadFieldValues(); //returned as array //We dont need this cookie, if the user logged in. if(!empty(VmConfig::get('cartCookieExpire',0))){ $this->setCookie('', time() - 10); } } if(isset($cartData['_inCheckOut'])) unset($cartData['_inCheckOut']); if(isset($cartData['_dataValidated'])) unset($cartData['_dataValidated']); if(isset($cartData['_confirmDone'])) unset($cartData['_confirmDone']); if(isset($cartData['_fromCart'])) unset($cartData['_fromCart']); if(isset($cartData['virtuemart_cart_id'])) $this->virtuemart_cart_id = $cartData['virtuemart_cart_id']; if($cartData and !empty($cartData['cartData'])){ $cartData['cartData'] = (object)vmJsApi::safe_json_decode($cartData['cartData'],true); $add = false; if($existingSession and !empty($cartData['cartData'])){ if(!empty($cartData['cartData']->cartProductsData) and is_array($cartData['cartData']->cartProductsData)){ foreach($cartData['cartData']->cartProductsData as $k => $product){ foreach($existingSession->cartProductsData as $kses => $productses){ //vmdebug('my stored products ',$productses); if($product['virtuemart_product_id']==$productses['virtuemart_product_id']){ //Okey, the id is already the same, so lets check the customProductData $diff = !$this->deepCompare($product['customProductData'],$productses['customProductData']); if(!$diff){ unset($cartData['cartData']->cartProductsData[$k]); //break; } else { $this->storeToDB = true; vmdebug('product variant is different, I add to cart'); } //unset($cartData['cartData']->cartProductsData[$k]); } else { $this->storeToDB = true; } //vmdebug('my stored products ',$product); } $this->productCartLoaded[$k] = true; } } foreach($cartData['cartData'] as $key=>$value){ if ($key == 'byDefaultBT' or $key =='byDefaultST'){ //continue; } else if($key == '_triesValidateCoupon'){ //We need this special handling for fallback reasons, we could also just delete stored carts when updating foreach($value as $k=>$v){ if($k<100) continue; if(!in_array($v,$existingSession->_triesValidateCoupon)){ $existingSession->_triesValidateCoupon[$k] = $v; } } } else { if(is_array($value)){ if($key=='cartProductsData' and count($value)>0 and VmConfig::get('showCartLoadedMsg',1)){ VmInfo('COM_VM_LOADED_STORED_CART'); } else if ($key=='BT' or $key=='ST'){ $existingSession->{$key} = $this->unsetDefaults($key, $existingSession->{$key}); } $existingSession->{$key} = array_merge( $value,(array)$existingSession->{$key}); } else if(empty($existingSession->{$key})){ $existingSession->{$key} = $cartData['cartData']->{$key}; } } } if(count($cartData['cartData']->cartProductsData)!=$existingSession->cartProductsData){ $this->storeToDB = true; } } } } public function storeCart($cartDataToStore = false){ if($this->tempCart) return; //quorvia dont store non completed carts for logged in users $Cartsdontsave = VmConfig::get('CartsDontSave', 0 ); if ($Cartsdontsave){ return; } //quorvia dont store non completed cart data for shoppergroup $CartsdontsaveShopperGroup = VmConfig::get('CartsDontSaveByshoppergroup', 0 ); if ($CartsdontsaveShopperGroup > 0 ){ if(!empty($this->user->shopper_groups) AND in_array($CartsdontsaveShopperGroup, $this->user->shopper_groups)) { return; } } $adminID = vmAccess::getBgManagerId(); $currentUser = JFactory::getUser(); //Better to replace the cookie technic against JWT $cartCookieExpire = VmConfig::get('cartCookieExpire',0); if( (!$currentUser->guest or !empty($cartCookieExpire) ) && (!$adminID || $adminID == $currentUser->id)){ if(!$cartDataToStore){ $data = $this->getCartDataToStore(); unset($data->productCartLoaded); if(!$currentUser->guest){ unset($data->BT); unset($data->ST); } //quorvia dont store cartfields e.g. TOS, Customer_note $CartsdontsaveCartfields = VmConfig::get('CartsDontSaveCartFields', 0 ); if($CartsdontsaveCartfields) { // this could just be more focussed if necessary // $data->cartfields['customer_note'] = ''; // unset($data->cartfields['tos']); $data->cartfields = ''; } $cartDataToStore = json_encode($data); } $cObj = new StdClass(); if(!empty($this->virtuemart_cart_id)) $cObj->virtuemart_cart_id = (int) $this->virtuemart_cart_id; $cObj->virtuemart_user_id = (int) $currentUser->id; $cObj->virtuemart_vendor_id = (int) $this->vendorId; $cObj->cartData = $cartDataToStore; if(!empty($cartCookieExpire) and $currentUser->guest and !headers_sent()){ $this->setCookie($cObj); } else if (!$currentUser->guest){ $model = new VmModel(); $carts = $model->getTable('carts'); vmdebug('storeCart by Table',$cObj); $carts->bindChecknStore($cObj); if(!empty($cObj->virtuemart_cart_id)){ $this->virtuemart_cart_id = $cObj->virtuemart_cart_id; } if(!empty($cartCookieExpire)){ $this->setCookie('', time() - 10); } } } } public function setCookie($cObj, $timeout = false){ if (headers_sent()) return; if (empty($cObj)) { $contEncode = null; $strlenCE = 0; } else { if (is_object($cObj)) { $cObj->modified_on = date('c'); } $contEncode = json_encode($cObj); $strlenCE = strlen($contEncode); } if( $strlenCE == 0 or (50 < $strlenCE and $strlenCE < 3600)) { $ver = (float)phpversion(); if($timeout===false) $timeout = time() + 86400 * VmConfig::get('cartCookieExpire',0); $domain = JUri::getInstance()->getHost(); $path = JUri::root(true); if ($ver > 7.2) { $arr_cookie_options = array ( 'expires' => $timeout, 'secure' => true, // or false //*/ 'httponly' => true, // or false 'samesite' => 'Strict', // None || Lax || Strict //*/ 'domain' => $domain, 'path'=> $path ); @setcookie('myCart', $contEncode, $arr_cookie_options); //vmdebug('storeCart by Cookie',time(),$arr_cookie_options); } else { @setcookie('myCart', $contEncode, $timeout, $path, $domain, 1, 1); //vmdebug('storeCart by Cookie'); } } if (empty($contEncode)) { $cookie = JFactory::getApplication()->input->cookie; if(method_exists($cookie, 'clear')){ $cookie->clear('myCart'); } } } public function deleteCart(){ $model = new VmModel(); $carts = $model->getTable('carts'); if(!empty($this->virtuemart_cart_id)){ $carts->delete($this->virtuemart_cart_id,'virtuemart_cart_id'); } else { $currentUser = JFactory::getUser(); if(!empty($currentUser->id)) { $carts->delete($currentUser->id); } } if(!empty(VmConfig::get('cartCookieExpire',0))){ $this->setCookie('', time() - 10); } } /** * Set the cart in the session * * @access public * @param array $cart the cart to store in the session */ public function setCartIntoSession($storeDb = false, $forceWrite = false) { if($this->tempCart) return; if($this->storeCartSession or $forceWrite){ if(!isset(self::$_session)) self::$_session = JFactory::getSession(); $sessionCart = $this->getCartDataToStore(); $sessionCart = json_encode($sessionCart); $multixcart = VmConfig::get('multixcart',0); if($multixcart!='byproduct'){ self::$_session->set('vmcart', $sessionCart,'vm'); } else { self::$_session->set('vmcart', $sessionCart,'vm'); self::$_session->set('vmcarts.'.$this->vendorId, $sessionCart,'vm'); } } if($this->storeCartSession and $storeDb){ $this->storeCart(); } if($forceWrite){ if (!headers_sent()) { session_write_close(); session_start(); //This just creates unneeded extra sql requests //self::$_session->close(); //self::$_session->start(); } } } public function getCartDataToStore(){ $sessionCart = new stdClass(); $sessionCart->cartProductsData = $this->cartProductsData; $sessionCart->vendorId = $this->vendorId; $sessionCart->lastVisitedCategoryId = $this->lastVisitedCategoryId; $sessionCart->virtuemart_shipmentmethod_id = $this->virtuemart_shipmentmethod_id; $sessionCart->virtuemart_paymentmethod_id = $this->virtuemart_paymentmethod_id; $sessionCart->automaticSelectedShipment = $this->automaticSelectedShipment; $sessionCart->automaticSelectedPayment = $this->automaticSelectedPayment; $sessionCart->order_number = $this->order_number; $sessionCart->BT = $this->BT; $sessionCart->ST = $this->ST; $sessionCart->cartfields = $this->cartfields; $sessionCart->couponCode = $this->couponCode; $sessionCart->_triesValidateCoupon = $this->_triesValidateCoupon; $sessionCart->order_language = $this->order_language; $sessionCart->pricesCurrency = $this->pricesCurrency; $sessionCart->paymentCurrency = $this->paymentCurrency; //private variables //We nee to store this, so that we now if a user logged in before $sessionCart->_guest = JFactory::getUser()->guest; $sessionCart->_inCheckOut = $this->_inCheckOut; $sessionCart->_inConfirm = $this->_inConfirm; $sessionCart->_redirected = $this->_redirected; $sessionCart->_dataValidated = $this->_dataValidated; $sessionCart->_confirmDone = $this->_confirmDone; $sessionCart->STsameAsBT = $this->STsameAsBT; $sessionCart->selected_shipto = $this->selected_shipto; $sessionCart->_fromCart = $this->_fromCart; $sessionCart->layout = $this->layout; $sessionCart->layoutPath = $this->layoutPath; $sessionCart->virtuemart_cart_id = $this->virtuemart_cart_id; $sessionCart->OrderIdOrderDone = $this->OrderIdOrderDone; $sessionCart->orderdoneHtml = $this->orderdoneHtml; $sessionCart->virtuemart_order_id = $this->virtuemart_order_id; $sessionCart->byDefaultBT = $this->byDefaultBT; $sessionCart->byDefaultST = $this->byDefaultST; $sessionCart->productCartLoaded = $this->productCartLoaded; $sessionCart->loadedCart = $this->loadedCart; $sessionCart->lastAddedProduct = $this->lastAddedProduct; return $sessionCart; } /** * Remove the cart from the session * * @author Max Milbers * @access public */ public function removeCartFromSession() { $carts = self::$_session->get('vmcarts', 0,'vm'); if($carts != 0){ unset($carts->{$this->vendorId}); self::$_session->set('vmcarts', $carts, 'vm'); } self::$_session->set('vmcart', 0, 'vm'); if(!empty(VmConfig::get('cartCookieExpire',0))){ $this->setCookie('', time() - 10); } } public function setDataValidation($valid=false) { $this->_dataValidated = $valid; } public function getDataValidated() { return $this->_dataValidated; } public function getInCheckOut() { return $this->_inCheckOut; } public function setOutOfCheckout(){ $this->_inCheckOut = false; $this->_dataValidated = false; $this->_blockConfirm = true; $this->_redirected = true; $this->_redirect = false; $this->storeCartSession = true; $this->setCartIntoSession(false,true); } public function blockConfirm(){ $this->_blockConfirm = true; } /** * For one page checkouts, disable with this the redirects * @param bool $bool */ public function setRedirectDisabled($bool = TRUE){ $this->_redirect_disabled = $bool; } /** * Add a product to the cart * * @author Max Milbers * @access public */ public function add($virtuemart_product_ids=null, $post = null) { $updateSession = true; if($post===null) $post = vRequest::getRequest(); if(empty($virtuemart_product_ids)){ $virtuemart_product_ids = vRequest::getInt('virtuemart_product_id'); //is sanitized } if (empty($virtuemart_product_ids)) { vmWarn('COM_VIRTUEMART_CART_ERROR_NO_PRODUCT_IDS'); return false; } else { if(is_array($virtuemart_product_ids)){ //2024 For legacy layouts with the doubled product ids in the layout if(!empty($post['quantity']) and is_array($post['quantity']) and count($post['quantity'])!=count($virtuemart_product_ids)){ $virtuemart_product_ids = array_unique($virtuemart_product_ids); } } else { $virtuemart_product_ids = array($virtuemart_product_ids); } } $products = array(); $customFieldsModel = VmModel::getModel('customfields'); vDispatcher::importVMPlugins('vmcustom'); //We may have to create a new cart for multicart, so we add them now $multixcart = VmConfig::get('multixcart',0); if($multixcart=='byproduct' ){ foreach ($virtuemart_product_ids as $p_key => $virtuemart_product_id) { if(empty($virtuemart_product_id)){ vmWarn('Product could not be added with virtuemart_product_id = 0'); unset($virtuemart_product_ids[$virtuemart_product_id]); continue; } /*else { $productData['virtuemart_product_id'] = (int)$virtuemart_product_id; }*/ if(!empty( $post['quantity'][$p_key])){ $productData['quantity'] = (int) $post['quantity'][$p_key]; } else if (count($virtuemart_product_ids) == 1) { $productData['quantity'] = vRequest::getInt('quantity',1); if(is_array($productData['quantity'])){ $productData['quantity'] = reset($productData['quantity']); } } else { continue; } $product = VirtueMartCart::getProduct($virtuemart_product_id, $productData['quantity']); /*$productTemp = $productModel->getProduct($virtuemart_product_id, true, false,true,$productData['quantity']); $productTemp->modificatorSum = null; $product = clone($productTemp);*/ if(!isset(self::$_carts[$product->virtuemart_vendor_id])){ VirtuemartCart::getCart(false, array(), NULL,$product->virtuemart_vendor_id); } } } //Iterate through the prod_id's and perform an add to cart for each one foreach ($virtuemart_product_ids as $p_key => $virtuemart_product_id) { $product = false; $updateSession = true; $productData = array(); if(empty($virtuemart_product_id)){ vmWarn('Product could not be added with virtuemart_product_id = 0'); return false; } else { $productData['virtuemart_product_id'] = (int)$virtuemart_product_id; } if(!empty( $post['quantity'][$p_key])){ $productData['quantity'] = (int) $post['quantity'][$p_key]; } else if (count($virtuemart_product_ids) == 1) { $productData['quantity'] = vRequest::getInt('quantity',1); if(is_array($productData['quantity'])){ $productData['quantity'] = reset($productData['quantity']); } } else { continue; } /*if(!empty( $post['customProductData'][$p_key])) { $customProductData = $post['customProductData'][$p_key]; } else */ if(!empty( $post['customProductData'][$virtuemart_product_id])) { $customProductData = $post['customProductData'][$virtuemart_product_id]; } else { $customProductData = array(); } //Now we check if the delivered customProductData is correct and add missing $product = VirtueMartCart::getProduct($virtuemart_product_id, $productData['quantity']); if(!$product) { vmdebug('cart add, no product found with id '.$virtuemart_product_id.' and quantity',$productData['quantity'] ); return false; } if($product->product_discontinued and !VmConfig::get('discontinuedPrdsBrowseable',1)){ vmError('COM_VM_CART_TRIED_ADDING_PRODUCT_DISCONTINUED'); continue; } $productData['virtuemart_vendor_id'] = $product->virtuemart_vendor_id; $product->customfields = $customFieldsModel->getCustomEmbeddedProductCustomFields($product->allIds,0,1); $customProductDataTmp=array(); foreach($product->customfields as $customfield){ // Some customfields may prevent the product being added to the cart $customFiltered = false; $addToCartReturnValues = vDispatcher::trigger('plgVmOnAddToCartFilter',array(&$product, &$customfield, &$customProductData, &$customFiltered)); if(!empty($product->remove)){ vmdebug('Remove product'); break; } if($customFiltered){ $customProductDataTmp=$customProductData; } else if(!$customFiltered && $customfield->is_input==1){ if(isset($customProductData[$customfield->virtuemart_custom_id][$customfield->virtuemart_customfield_id])){ if(is_array($customProductData[$customfield->virtuemart_custom_id][$customfield->virtuemart_customfield_id])){ foreach($customProductData[$customfield->virtuemart_custom_id][$customfield->virtuemart_customfield_id] as $i=>$customData){ //$value = vmFilter::hl( $customData,array('deny_attribute'=>'*')); //to strong /* $value = preg_replace('@<[\/\!]*?[^<>]*?>@si','',$value);//remove all html tags */ //lets use instead $value = JComponentHelper::filterText($customData); $value = (string)preg_replace('#on[a-z](.+?)\)#si','',$value);//replace start of script onclick() onload()... $value = trim(str_replace('"', ' ', $value),"'") ; $customProductData[$customfield->virtuemart_custom_id][$customfield->virtuemart_customfield_id][$i] = (string)preg_replace('#^\'#si','',$value); } } if(!isset($customProductDataTmp[$customfield->virtuemart_custom_id])) $customProductDataTmp[$customfield->virtuemart_custom_id] = array(); $customProductDataTmp[$customfield->virtuemart_custom_id][$customfield->virtuemart_customfield_id] = $customProductData[$customfield->virtuemart_custom_id][$customfield->virtuemart_customfield_id]; } else if(isset($customProductData[$customfield->virtuemart_custom_id])) { $customProductDataTmp[$customfield->virtuemart_custom_id] = $customProductData[$customfield->virtuemart_custom_id]; //vmdebug('my customp product data ',$customProductData[$customfield->virtuemart_custom_id]); } } else { if(!isset($customProductDataTmp[$customfield->virtuemart_custom_id])){ $customProductDataTmp[$customfield->virtuemart_custom_id] = array(); } else if(!is_array($customProductDataTmp[$customfield->virtuemart_custom_id])){ $customProductDataTmp[$customfield->virtuemart_custom_id] = array($customProductDataTmp[$customfield->virtuemart_custom_id]); } if(!isset($customProductDataTmp[$customfield->virtuemart_custom_id])){ $customProductDataTmp[$customfield->virtuemart_custom_id][(int)$customfield->virtuemart_customfield_id] = false; } } } $productData['customProductData'] = $customProductDataTmp; if(!empty($product->remove)){ continue; } $found = false; $unsetA = array(); foreach(self::$_carts as $vendorId => $cart) { if($multixcart=='byproduct' /*or $multixcart =='multicart'*/){ if($cart->vendorId != $productData['virtuemart_vendor_id']) continue; } //$cart->cartProductsData //Now lets check if there is already a product stored with the same id, if yes, increase quantity and recalculate foreach( $cart->cartProductsData as $k => $cartProductData ) { $cartProductData = (array)$cartProductData; if(empty( $cartProductData['virtuemart_product_id'] )) { $unsetA[] = $k; $errorMsg = true; } else { if($cartProductData['virtuemart_product_id'] == $productData['virtuemart_product_id']) { //Okey, the id is already the same, so lets check the customProductData $diff = !$cart->deepCompare( $cartProductData['customProductData'], $productData['customProductData'] ); if(!$diff) { vmdebug( 'my productCartLoaded ', $k, $cart->productCartLoaded ); if(!empty( $cart->productCartLoaded[$k] )) { $newTotal = (float)$productData['quantity']; //We assume the customer entered a correct new quantity. unset( $cart->productCartLoaded[$k] ); } else { $newTotal = (float)$cartProductData['quantity'] + (float)$productData['quantity']; } if(!$product) $product = VirtueMartCart::getProduct( (int)$productData['virtuemart_product_id'], $cartProductData['quantity'] ); if(empty( $product->virtuemart_product_id )) { vmWarn( 'COM_VIRTUEMART_PRODUCT_NOT_FOUND' ); $unsetA[] = $k; } else { $cart->checkForQuantities( $product, $newTotal ); vmdebug( "add to cart did checkForQuantities", $newTotal, $productData['quantity'] ); $product->quantityAdded = $newTotal - $cartProductData['quantity']; $product->quantity = $newTotal; $cartProductData['quantity'] = $newTotal; $cart->cartProductsData[$k] = $cartProductData; $cart->_productAdded = true; $cart->lastAddedProduct = $product->virtuemart_product_id; vmdebug( 'add to cart did $product->quantityAdded ', $cartProductData['quantity'] ); } $found = TRUE; break; } else { vmdebug( 'product variant is different, I add to cart' ); $cart->_productAdded = true; $cart->lastAddedProduct = $product->virtuemart_product_id; } } } //add products to remove to array if($cartProductData['quantity'] == 0) { $unsetA[] = $k; $this->_productAdded = true; } } if(!$found) { if(!$product) $product = VirtueMartCart::getProduct( (int)$productData['virtuemart_product_id'], $productData['quantity'] ); if(!empty( $product->virtuemart_product_id )) { $cart->checkForQuantities( $product, $product->quantity ); //vmdebug( 'my $productData $productData ', $productData ); if(!empty( $product->quantity )) { $productData['quantity'] = $product->quantity; $cart->cartProductsData[] = $productData; } else { $errorMsg = true; } } else { $errorMsg = true; } } if($product) { $products[] = $product; $cart->_productAdded = true; $cart->lastAddedProduct = $product->virtuemart_product_id; } //Remove the products which have quantity=0 foreach( $unsetA as $v ) { unset( $cart->cartProductsData[$v] ); } vDispatcher::trigger('plgVmOnAddToCart',array(&$cart)); //if ($updateSession== false) return false ; $cart->_dataValidated = false; // End Iteration through Prod id's $cart->setCartIntoSession(true); self::$_carts[$vendorId] = &$cart; } } return $products; } static public function deepCompare($a,$b) { if(is_object($a) && is_object($b)) { if(get_class($a)!=get_class($b)) return false; foreach($a as $key => $val) { if(!self::deepCompare($val,$b->{$key})) return false; } return true; } else if(is_array($a) && is_array($b)) { while(!is_null(key($a)) && !is_null(key($b))) { if (key($a)!==key($b) || !self::deepCompare(current($a),current($b))) return false; next($a); next($b); } return is_null(key($a)) && is_null(key($b)); } else return $a===$b; } /** * Remove a product from the cart * * @author RolandD * @param array $cart_id the cart IDs to remove from the cart * @access public */ public function removeProductCart($prod_id=0) { // Check for cart IDs if (empty($prod_id)) $prod_id = vRequest::getInt('cart_virtuemart_product_id'); unset($this->products[$prod_id]); if(isset($this->cartProductsData[$prod_id])){ // hook for plugin action "remove from cart" vDispatcher::importVMPlugins('vmcustom'); $addToCartReturnValues = vDispatcher::trigger('plgVmOnRemoveFromCart',array($this,$prod_id)); unset($this->cartProductsData[$prod_id]); if(!empty($cart->couponCode)){ $cart->setCouponCode($cart->couponCode); } $this->setCartIntoSession(true); return true; } else { vmdebug('removeProductCart $prod_id '.$prod_id,$this->cartProductsData); return false; } } /** * Update a product in the cart * * @author Max Milbers * @param array $cart_id the cart IDs to remove from the cart * @access public */ public function updateProductCart() { $quantities = vRequest::getInt('quantity'); if(empty($quantities)) return false; $updated = false; foreach($quantities as $key=>$quantity){ if (isset($this->cartProductsData[$key]) and !empty($quantity) and !isset($_POST['delete_'.$key])) { if($quantity!=$this->cartProductsData[$key]['quantity']){ $this->cartProductsData[$key]['quantity'] = $quantity; $updated = true; $this->_productAdded = true; vmInfo('COM_VIRTUEMART_PRODUCT_UPDATED_SUCCESSFULLY'); } } else { unset($this->cartProductsData[$key]); $this->_productAdded = true; vmInfo('COM_VIRTUEMART_PRODUCT_REMOVED_SUCCESSFULLY'); $updated = true; } } $this->setCartIntoSession($updated); return $updated; } /** * Validate the coupon code. If ok,. set it in the cart * @param string $coupon_code Coupon code as entered by the user * TODO Change the coupon total/used in DB ? * @access public * @return string On error the message text, otherwise an empty string */ public function setCouponCode($coupon_code) { $db = JFactory::getDbo(); $currentUser = JFactory::getUser(); $allow_coupon = 0; $coupon_details = CouponHelper::getCouponDetails( $coupon_code ); $userAttempts = 0; if($currentUser->id) { $query = $db->getQuery( true ); $query->select( 'count(vo.virtuemart_order_id)' ); $query->from( $db->quoteName( '#__virtuemart_orders', 'vo' ) ); $query->join( 'INNER', $db->quoteName( '#__virtuemart_vmusers', 'vv' ).' ON ('.$db->quoteName( 'vo.virtuemart_user_id' ).' = '.$db->quoteName( 'vv.virtuemart_user_id' ).')' ); $query->where( 'vo.virtuemart_user_id = '.$currentUser->id.'' ); $db->setQuery( $query ); $userAttempts = $db->loadResult(); } if($userAttempts>0 and ( !empty($coupon_details->virtuemart_coupon_max_attempt_per_user) and $coupon_details->virtuemart_coupon_max_attempt_per_user>0 )) { if($userAttempts>=$coupon_details->virtuemart_coupon_max_attempt_per_user) { $this->clearCoupon(); return 'Maximum coupon usage limit reached, please try different code.'; } } if(!empty( $coupon_details->virtuemart_shoppergroup_ids ) || !empty( $coupon_details->virtuemart_shopper_ids )) { if(!empty( $coupon_details->virtuemart_shoppergroup_ids )) { $query = $db->getQuery( true ); $query->select( $db->quoteName( array('virtuemart_user_id', 'virtuemart_shoppergroup_id') ) ); $query->from( $db->quoteName( '#__virtuemart_vmuser_shoppergroups' ) ); $query->where( 'virtuemart_user_id = '.$currentUser->id.' AND virtuemart_shoppergroup_id IN ('.$coupon_details->virtuemart_shoppergroup_ids.')' ); $db->setQuery( $query ); $isNotAllowed = $db->loadObjectList(); $allow_coupon = ($isNotAllowed) ? 0 : 1; } if(!empty( $coupon_details->virtuemart_shopper_ids ) && $allow_coupon == 0) { $query = $db->getQuery( true ); $query->select( $db->quoteName( array('virtuemart_user_id') ) ); $query->from( $db->quoteName( '#__virtuemart_vmusers' ) ); $query->where( 'virtuemart_user_id IN ('.$coupon_details->virtuemart_shopper_ids.')' ); $db->setQuery( $query ); $allowedUsersList = $db->loadColumn(); $allow_coupon = (in_array( $currentUser->id, $allowedUsersList )) ? 1 : 0; } if(empty( $coupon_details->virtuemart_shoppergroup_ids ) && $allow_coupon == 0) { $virtuemart_shoppergroup_ids_arr = explode( ',', $coupon_details->virtuemart_shoppergroup_ids ); if(($currentUser->id && in_array( 2, $virtuemart_shoppergroup_ids_arr )) || (!$currentUser->id && in_array( 1, $virtuemart_shoppergroup_ids_arr ))) { $allow_coupon = 1; } } } else if(empty( $coupon_details->virtuemart_shoppergroup_ids ) && empty( $coupon_details->virtuemart_shopper_ids )) { $allow_coupon = 1; } if(!empty( $coupon_details->virtuemart_product_ids ) || !empty( $coupon_details->virtuemart_category_ids )) { $allowed_product_ids = array(); if(!empty($coupon_details->virtuemart_product_ids) and !is_array($coupon_details->virtuemart_product_ids)){ $allowed_product_ids = explode( ',', $coupon_details->virtuemart_product_ids ); } $allowed_productcat_ids = array(); if(!empty($coupon_details->virtuemart_category_ids)){ $allowed_productcat_ids = explode( ',', $coupon_details->virtuemart_category_ids ); } $sizeof_cartitems_by_product = count( $this->productsQuantity ); $allow_coupon_byproduct = 0; for( $i = 0; $i<$sizeof_cartitems_by_product; $i++ ) { if( (!empty($allowed_product_ids) and in_array( $this->cartPrices[$i]['virtuemart_product_id'], $allowed_product_ids )) || (!empty($allowed_productcat_ids) and array_intersect( $this->products[$i]->categories, $allowed_productcat_ids )) ) { $allow_coupon_byproduct = 1; break; } } $allow_coupon = ($allow_coupon_byproduct == 1) ? 1 : 0; } if($allow_coupon == 0) { $this->clearCoupon(); return 'Coupon code not valid, please try different code.'; } if(empty( $coupon_code ) or $coupon_code == vmText::_( 'COM_VIRTUEMART_COUPON_CODE_ENTER' )) { $this->clearCoupon(); return false; } /*else if($this->couponCode == $coupon_code) { return; }*/ $this->prepareCartData(); $msg = $this->validateCoupon( $coupon_code ); //$this->getCartPrices(); if(empty( $msg )) { $this->couponCode = $coupon_code; $this->cartData['couponCode'] = $coupon_code; $this->prepareCartData( true ); $this->setCartIntoSession( true, true ); return vmText::_( 'COM_VIRTUEMART_CART_COUPON_VALID' ); } else { $this->clearCoupon(); $this->prepareCartData( true ); $this->setCartIntoSession( true, true ); return $msg; } } public function validateCoupon ($coupon_code) { $timeDeleteTries = time() - (24*60*60); foreach( $this->_triesValidateCoupon as $k => $v ) { if($k<8 or $k<$timeDeleteTries) { unset( $this->_triesValidateCoupon[$k] ); } } $couponTryTime = (string)time(); if(!in_array($coupon_code,$this->_triesValidateCoupon)){ $this->_triesValidateCoupon[$couponTryTime] = $coupon_code; } if(count($this->_triesValidateCoupon)<8){ $msg = CouponHelper::ValidateCouponCode($coupon_code, $this->cartPrices['salesPrice']); if(empty($msg)){ $this->_triesValidateCoupon = array(); //A valid couponcode means we had a normal customer } } else{ $msg = vmText::_('COM_VIRTUEMART_CART_COUPON_TOO_MANY_TRIES'); } if (!empty($msg)) { $this->_dataValidated = false; $this->_blockConfirm = true; return $msg; } return ''; } public function clearCoupon(){ $this->couponCode = ''; $this->cartData['couponCode'] = ''; } public function setMethod($type,$force=false, $redirect=true, $id = null) { if($type){ $idN = 'virtuemart_paymentmethod_id'; $task = 'editpayment'; $vmplugin = 'vmpayment'; } else { $idN = 'virtuemart_shipmentmethod_id'; $task = 'editshipment'; $vmplugin = 'vmshipment'; } if(!isset($id)) $id = vRequest::getInt($idN, $this->{$idN}); if($this->{$idN} != $id or (!empty($id) and $force)){ $this->{$idN} = $id; JPluginHelper::importPlugin($vmplugin); //Add a hook here for other methods, checking the data of the choosed plugin $msg = ''; //@Todo we need actually &this,$msg for both triggers. if($type){ $_retValues = vDispatcher::trigger('plgVmOnSelectCheckPayment', array( $this, &$msg)); } else { $cart = &$this; $_retValues = vDispatcher::trigger('plgVmOnSelectCheckShipment', array( &$cart )); } $dataValid = true; foreach ($_retValues as $_retVal) { if ($_retVal === true ) { $this->setCartIntoSession(); // Plugin completed succesfull; nothing else to do return true; break; } else if ($_retVal === false ) { if ($redirect) { $app = JFactory::getApplication(); $app->redirect(JRoute::_('index.php?option=com_virtuemart&view=cart&task='.$task,$this->useXHTML,$this->useSSL), $msg); break; } else { return false; } } } $this->setCartIntoSession(); } } /** * Check the selected shipment data and store the info in the cart * @param integer $shipment_id Shipment ID taken from the form data * @author Max Milbers */ public function setShipmentMethod($force=false, $redirect=true, $virtuemart_shipmentmethod_id = null) { $this->setMethod(false, $force, $redirect, $virtuemart_shipmentmethod_id); } public function setPaymentMethod($force=false, $redirect=true, $virtuemart_paymentmethod_id = null) { $this->setMethod(true, $force, $redirect, $virtuemart_paymentmethod_id); } function confirmDone() { //Check if data has changed meanwhile $cHash = $this->getCartHash(); if($cHash != $this->_dataValidated){ $this->_dataValidated = false; vmInfo('COM_VIRTUEMART_CART_CHECKOUT_DATA_CHANGED'); $app = JFactory::getApplication(); $app->redirect(JRoute::_('index.php?option=com_virtuemart&view=cart'.$this->getLayoutUrlString(), FALSE) ); } //Final check $this->checkoutData(false, true); $app = JFactory::getApplication(); if ($this->_dataValidated == $cHash) { $this->_confirmDone = true; $this->orderDetails = 0; if($this->confirmedOrder()){ $this->layout = 'orderdone'; $this->setCartIntoSession(); $currentUser = JFactory::getUser(); if(!$currentUser->guest) { $um = VmModel::getModel('user'); $this->BT['address_type'] = 'BT'; $um->storeAddress($this->BT); } return true; } else { vmdebug('Confirmed order returned false'); $this->_dataValidated = false; $this->_confirmDone = false; $this->setCartIntoSession(); vmWarn('COM_VIRTUEMART_CART_CHECKOUT_DATA_NOT_VALID'); $app->redirect(JRoute::_('index.php?option=com_virtuemart&view=cart', FALSE) ); } } $this->_dataValidated = false; $this->_confirmDone = false; $this->setCartIntoSession(); vmWarn('COM_VIRTUEMART_CART_CHECKOUT_DATA_NOT_VALID'); $app->redirect(JRoute::_('index.php?option=com_virtuemart&view=cart'.$this->getLayoutUrlString(), FALSE) ); } private function redirecter($relUrl,$redirectMsg){ $this->_dataValidated = false; $app = JFactory::getApplication(); if($this->_redirect and !$this->_redirected and !$this->_redirect_disabled){ $this->_redirected = true; $this->setCartIntoSession( false, false); if(isset($redirectMsg))vmWarn($redirectMsg); $app->redirect(JRoute::_($relUrl,$this->useXHTML,$this->useSSL) ); return true; } else { $this->_redirected = false; $this->_inCheckOut = false; $this->setCartIntoSession(false, false); return false; } } public function getLayoutUrlString($request=false){ if($request){ $layoutName = vRequest::getCmd('layout', 'default'); } else { $layoutName = $this->layout; } if(!empty($layoutName) and $layoutName!='default'){ return '&layout='.$layoutName; } else { return ''; } } public function checkoutData($redirect = true, $forceStoreSession = false) { if($this->_redirected){ $this->_redirect = false; } else { $this->_redirect = $redirect; } $layoutName = ''; if(!empty($this->layout) and $this->layout!='default' and $this->layout!='orderdone') { $layoutName = '&layout=' . $this->layout; } vmdebug('checkoutData my layoutname ',$layoutName); $this->_inCheckOut = true; //This prevents that people checkout twice $this->setCartIntoSession(false,$forceStoreSession); // Check if a minimun purchase value is set if (($redirectMsg = $this->checkPurchaseValue()) != null) { $this->_inCheckOut = false; return $this->redirecter('index.php?option=com_virtuemart&view=cart'.$layoutName , $redirectMsg); } $this->checkForCartQuantities(); $currentUser = JFactory::getUser(); $validUserDataBT = self::validateUserData(); if ($validUserDataBT!==true) { //Important, we can have as result -1,false and true. return $this->redirecter('index.php?option=com_virtuemart&view=user&task=editaddresscart&addrtype=BT' , ''); } if(!empty($this->STsameAsBT) or (!$currentUser->guest and empty($this->selected_shipto))){ //Guest // quorvia consider whether the store wants to populate empty ST address with the BT address $populate_empty_ST = VmConfig::get('populateEmptyST', 1 ); if($this->_confirmDone or $populate_empty_ST ){ //quorvia added to prevent population of ST address with BT address before the cart is confirmed $this->ST = $this->BT; } else { $this->ST = 0; } } else { if ($this->selected_shipto >0 ) { $userModel = VmModel::getModel('user'); $stData = $userModel->getUserAddressList($currentUser->id, 'ST', $this->selected_shipto); if(isset($stData[0]) and is_object($stData[0])){ $stData = get_object_vars($stData[0]); if($this->validateUserData('ST', $stData)>0){ $this->ST = $stData; } } else { $this->selected_shipto = 0; $this->ST = $this->BT; } } //Only when there is an ST data, test if all necessary fields are filled $validUserDataST = self::validateUserData('ST'); if ($validUserDataST!==true) { return $this->redirecter('index.php?option=com_virtuemart&view=user&task=editaddresscart&addrtype=ST' , ''); } } $usersConfig = JComponentHelper::getParams( 'com_users' ); $useractivation = $usersConfig->get( 'useractivation' ); if ($currentUser ->block) { if($useractivation!=1){ $redirectMsg = vmText::_('JERROR_NOLOGIN_BLOCKED'); return $this->redirecter('index.php?option=com_virtuemart&view=user&task=editaddresscart&addrtype=BT' , $redirectMsg); } } if(VmConfig::get('oncheckout_only_registered',0)) { if(empty($currentUser->id)) { $redirectMsg = vmText::_('COM_VIRTUEMART_CART_ONLY_REGISTERED'); return $this->redirecter('index.php?option=com_virtuemart&view=user&task=editaddresscart&addrtype=BT' , $redirectMsg); } } // Test Coupon if (!empty($this->couponCode)) { $redirectMsg = $this->validateCoupon($this->couponCode); if (!empty($redirectMsg)) { $this->clearCoupon(); $this->_inCheckOut = false; $this->setCartIntoSession(); return $this->redirecter('index.php?option=com_virtuemart&view=cart'.$layoutName , $redirectMsg); } } $redirectMsg = ''; //Test Shipment and show shipment plugin if (empty($this->virtuemart_shipmentmethod_id)) { return $this->redirecter('index.php?option=com_virtuemart&view=cart&task=edit_shipment' , $redirectMsg); } else { vDispatcher::importVMPlugins('vmshipment'); //Add a hook here for other shipment methods, checking the data of the choosed plugin $retValues = vDispatcher::trigger('plgVmOnCheckoutCheckDataShipment', array( $this)); foreach ($retValues as $retVal) { if ($retVal === true) { break; // Plugin completed succesfull; nothing else to do } elseif ($retVal === false) { // Missing data, ask for it (again) return $this->redirecter('index.php?option=com_virtuemart&view=cart&task=edit_shipment' , $redirectMsg); // NOTE: inactive plugins will always return null, so that value cannot be used for anything else! } } } //Test Payment and show payment plugin if(!empty($this->cartPrices['salesPrice']) and $this->cartPrices['salesPrice']>0.0){ if (empty($this->virtuemart_paymentmethod_id)) { return $this->redirecter('index.php?option=com_virtuemart&view=cart&task=editpayment' , $redirectMsg); } else /*if ($redirect)*/ { vDispatcher::importVMPlugins('vmpayment'); //Add a hook here for other payment methods, checking the data of the choosed plugin $retValues = vDispatcher::trigger('plgVmOnCheckoutCheckDataPayment', array( $this)); foreach ($retValues as $retVal) { if ($retVal === true) { break; // Plugin completed succesful; nothing else to do } elseif ($retVal === false) { // Missing data, ask for it (again) return $this->redirecter('index.php?option=com_virtuemart&view=cart&task=editpayment' , $redirectMsg); // NOTE: inactive plugins will always return null, so that value cannot be used for anything else! } } } /*else { }*/ } $validUserDataCart = self::validateUserData('cartfields',$this->cartfields,$this->_redirect); if($validUserDataCart!==true){ if($this->_redirect){ $this->_inCheckOut = false; $redirectMsg = null; vmdebug('_redirect due missing cartfields '.$layoutName,$validUserDataCart); return $this->redirecter('index.php?option=com_virtuemart&view=cart'.$layoutName , $redirectMsg); } $this->_blockConfirm = true; } else { //Atm a bit dirty. We store this information in the BT order_userinfo, so we merge it here, it gives also //the advantage, that plugins can easily deal with it. //$this->BT = array_merge((array)$this->BT,(array)$this->cartfields); } //Either we use here $this->_redirect, or we redirect always directly, atm we check the boolean _redirect if (count($this->cartProductsData) == 0) { $this->_inCheckOut = false; return $this->redirecter('index.php?option=com_virtuemart&view=cart', vmText::_('COM_VIRTUEMART_CART_NO_PRODUCT')); } //Show cart and checkout data overview if($this->_redirected){ //$this->_redirected = false; } else { $this->_inCheckOut = false; } if($this->_blockConfirm){ $this->_dataValidated = false; $this->_inCheckOut = false; return $this->redirecter('index.php?option=com_virtuemart&view=cart'.$layoutName,''); } else { $this->_dataValidated = $this->getCartHash(); $this->_inCheckOut = false; $this->setCartIntoSession(false, false); if ($this->_redirect) { $app = JFactory::getApplication(); vmInfo('COM_VIRTUEMART_CART_CHECKOUT_DONE_CONFIRM_ORDER'); $app->redirect(JRoute::_('index.php?option=com_virtuemart&view=cart'.$layoutName, FALSE)); } else { return true; } } } /** * Check if a minimum purchase value for this order has been set, and if so, if the current * value is equal or hight than that value. * @author Oscar van Eijk * @return An error message when a minimum value was set that was not eached, null otherwise */ private function checkPurchaseValue() { $this->prepareVendor(); if ($this->vendor->vendor_min_pov > 0) { $this->getCartPrices(); if ($this->cartPrices['salesPrice'] < $this->vendor->vendor_min_pov) { $currency = CurrencyDisplay::getInstance(); return vmText::sprintf('COM_VIRTUEMART_CART_MIN_PURCHASE', $currency->priceDisplay($this->vendor->vendor_min_pov)); } } return null; } /** * Test userdata if valid * * @author Max Milbers * @param String if BT or ST * @param Object If given, an object with data address data that must be formatted to an array * @return redirectMsg, if there is a redirectMsg, the redirect should be executed after */ public function validateUserData($type='BT', $obj = null,$redirect = false) { $usersModel = VmModel::getModel('user'); if($obj==null){ return $usersModel->validateUserData($this->{$type},$type,$redirect); } else { return $usersModel->validateUserData($obj,$type,$redirect); } } /** * This function is called, when the order is confirmed by the shopper. * * Here are the last checks done by payment plugins. * The mails are created and send to vendor and shopper * will show the orderdone page (thank you page) * */ function confirmedOrder() { //Just to prevent direct call if ($this->_dataValidated and $this->_confirmDone and !$this->_inCheckOut) { if($this->_inConfirm) return false; //We set this in the trigger of the plugin. so old plugins keep the old behaviour $orderModel = VmModel::getModel('orders'); $this->orderdoneHtml = false; $this->virtuemart_order_id = $orderModel->createOrderFromCart($this); if (!$this->virtuemart_order_id) { $mainframe = JFactory::getApplication(); //vmError('No order created '.$orderModel->getError()); $mainframe->redirect(JRoute::_('index.php?option=com_virtuemart&view=cart', FALSE) ); } $orderId = $this->virtuemart_order_id; //$orderDetails = $orderModel->getMyOrderDetails($this->virtuemart_order_id,$this->order_number,$this->order_pass); $orderDetails = $orderModel->getOrder($this->virtuemart_order_id); if(!$orderDetails or empty($orderDetails['details'])){ echo vmText::_('COM_VIRTUEMART_CART_ORDER_NOTFOUND'); return false; } vDispatcher::importVMPlugins('vmpayment'); $this->orderDetails = $orderDetails; $returnValues = vDispatcher::trigger('plgVmConfirmedOrder', array(&$this, $orderDetails)); if($this->_blockConfirmedCheckout){ VmInfo('Checkout blocked by Payment plugin'); return false; } if($this->orderdoneHtml===false){ $orderDoneHtml = vRequest::get('html', false); if($orderDoneHtml){ $this->orderdoneHtml = $orderDoneHtml; } else { $this->orderdoneHtml = vmText::_('COM_VIRTUEMART_ORDER_PROCESSED'); } } // may be redirect is done by the payment plugin (eg: paypal) // if payment plugin echos a form, false = nothing happen, true= echo form , // 1 = cart should be emptied, 0 cart should not be emptied $this->setCartIntoSession(); return $orderId; } else { vmdebug('one condition not meet for confirmedOrder',$this->_dataValidated, (int)$this->_confirmDone, (int)$this->_inCheckOut); } return false; } public function getCartHash(){ return md5(serialize($this->cartProductsData) . serialize($this->BT). ($this->STsameAsBT) ? '': serialize($this->ST) . $this->STsameAsBT . $this->order_language. $this->selected_shipto. serialize($this->cartPrices). $this->virtuemart_shipmentmethod_id . (!empty($this->cartData['shipmentName']) ? $this->cartData['shipmentName'] : '') . $this->virtuemart_paymentmethod_id . (!empty($this->cartData['paymentName']) ? $this->cartData['paymentName'] : '') . $this->customer_number ); } /** * emptyCart: Used for payment handling. * * @author Valerie Cartan Isaksen * */ public function emptyCart(){ self::emptyCartValues($this); } /** * emptyCart: Used for payment handling. * * @author Valerie Cartan Isaksen * */ static public function emptyCartValues( &$cart, $session = true){ //We dont need to do this, if the cart was just emptied if(empty($cart->products) and empty($cart->cartProductsData) and empty($cart->cartData) ){ return; } vmTrace('emptyCartValues'); //if we used a coupon, we must set it in final use now $couponCode = ''; if(!empty($cart->couponCode)){ $couponCode = $cart->couponCode; } else if(!empty($cart->cartData['couponCode'])){ $couponCode = $cart->cartData['couponCode']; } if(!empty($couponCode)){ CouponHelper::setInUseCoupon($couponCode, true, 1); } //We delete the old stuff $cart->products = array(); $cart->cartProductsData = array(); $cart->cartData = array(); $cart->cartPrices = array(); $cart->cartfields = array(); $cart->_inCheckOut = false; $cart->_dataValidated = false; $cart->_confirmDone = false; $cart->couponCode = ''; $cart->order_language = ''; $cart->virtuemart_shipmentmethod_id = 0; //OSP 2012-03-14 $cart->virtuemart_paymentmethod_id = 0; $cart->order_number=null; $cart->_fromCart = false; $cart->_inConfirm = false; $cart->totalProduct=false; $cart->productsQuantity=array(); $cart->OrderIdOrderDone = $cart->virtuemart_order_id; //We delete this one later in order done, it should not hurt,... $cart->virtuemart_order_id = false; $cart->layout = VmConfig::get('cartlayout','default'); if($session){ $cart->deleteCart(); $cart->setCartIntoSession(); } //It looks like we need this to prevent, that the cart gets the old layout back (orderdone) $cart = VirtueMartCart::getCart(true); } function resetEntireCart(){ self::emptyCartValues($this, false); $this->user = false; $this->customer_number = ''; $this->BT = array(); $this->ST = array(); $this->BTaddress = array(); $this->STaddress = array(); $this->deleteCart(); $this->virtuemart_cart_id = 0; $this->setCartIntoSession(false,true); self::$_carts[$this->vendorId] = $this; } function saveCartFieldsInCart(){ $userFieldsModel = VmModel::getModel('userfields'); $cartFields = $userFieldsModel->getUserFields( 'cart' , array('delimiters' => true, 'captcha' => true, 'system' => false) , array('delimiter_userinfo', 'name','username', 'password', 'password2', 'address_type_name', 'address_type', 'user_is_vendor', 'agreed')); foreach ($cartFields as $fld) { if(!empty($fld->name)){ $name = $fld->name; if($fld->type=='checkbox'){ $tmp = vRequest::getInt($name,0); $this->cartfields[$name] = $tmp; } else { $tmp = vRequest::getString($name,null); if(isset($tmp)){ if(!empty($tmp)){ if(is_array($tmp)){ $tmp = implode("|*|",$tmp); } $tmp = vRequest::vmSpecialChars($tmp); //$tmp = (string)preg_replace('#on[a-z](.+?)\)#si','',$tmp);//replace start of script onclick() onload()... } $this->cartfields[$name] = $tmp; //vmdebug('Store $this->cartfields[$name] '.$name.' '.$tmp); } } } } $this->BT = array_merge((array)$this->BT,(array)$this->cartfields); $this->setCartIntoSession(); } function saveAddressInCart($data, $type, $putIntoDb = true,$prefix='') { $userFieldsModel = VmModel::getModel('userfields'); if ($type == 'STaddress' or $type == 'BTaddress'){ vmTrace('STaddress found, seek and destroy'); } $prepareUserFields = $userFieldsModel->getUserFieldsFor('cart',$type); if(!is_array($data)){ $data = get_object_vars($data); } if ($type =='ST') { $this->STsameAsBT = 0; } else { // BT if(empty($data['email'])){ $jUser = JFactory::getUser(); if(!empty($jUser->email)) $data['email'] = $jUser->email; } } $address = array(); foreach ($prepareUserFields as $fld) { if(!empty($fld->name)){ $name = $fld->name; if(isset($data[$prefix.$name])){ //We directly overwrite the $data array $address[$name] = $data[$prefix.$name] = $userFieldsModel->prepareFieldDataSave($fld, $data, $prefix); } else { //vmdebug('Data not found for type '.$type.' and name '.$prefix.$name.' '); } } } //dont store passwords in the session unset($address['password']); unset($address['password2']); //We reset the default array $this->{'byDefault'.$type} = array(); $this->{$type} = $address; if($putIntoDb){ $this->setCartIntoSession(true, true); } vmdebug('saveAddressInCart ',(int)$putIntoDb,$this->STsameAsBT,$type,$this->{$type}); } /** * Returns ST address considering the set options, with fallback * @author Max Milbers */ public function getST($name=0,$FBBT=true){ $addr = $this->ST; if($this->STsameAsBT == 0){ if($FBBT){ if($name!==0){ if(!isset($this->ST[$name])){ $addr = $this->BT; } } else if($this->ST == 0){ //vmdebug('getST ST=0, use BT'); $addr = $this->BT; } } } else { $addr = $this->BT; //vmdebug('getST STsameAsBT is set, use BT',$addr); } if($name!==0){ return isset($addr[$name]) ? $addr[$name] : ''; } else { return $addr!==0 ? $addr : array(); } } /** * This function controlls the visible methods in the cart and sets the method automatically. * @author Valérie Isaksen, Max Milbers * @param $type * @return bool */ function checkAutomaticSelectedPlug($type){ $vm_method_name = 'virtuemart_'.$type.'method_id'; //if(!empty($this->$vm_method_name)) return false; if (count($this->products) == 0 ) { return false; } $setAutomatic = VmConfig::get('set_automatic_'.$type,'0'); if ($setAutomatic =='-1') { return false; } $d = VmConfig::$_debug; if(VmConfig::get('debug_enable_methods',false)){ VmConfig::$_debug = 1; } $trigger = 'plgVmOnCheckAutomaticSelected'; if(VmConfig::get('checkAutomaticLegacy',false)){ $trigger .= ucfirst($type); } $counter=0; $returnValues = vDispatcher::trigger($trigger, array( $this,$this->cartPrices, &$counter, $type)); //vmdebug('checkAutomaticSelectedPlug my return value '.$type,$returnValues); $vm_autoSelected_name = 'automaticSelected'.ucfirst($type); $this->{$vm_autoSelected_name}=false; $nb = 0; $method_id = array(); foreach ($returnValues as $returnValue) { if ( isset($returnValue )) { if(is_array($returnValue)){ foreach($returnValue as $method){ $nb ++; $method_id[] = $method; } } else if ($returnValue){ $nb ++; $method_id[] = $returnValue; } else if ( $returnValue === 0) { //Here are the old plugins //$this->{$vm_autoSelected_name}=true; vmdebug('Old plugin detected, no method given'); } } } //vmdebug('checkAutomaticSelectedPlug my $method_ids '.$type,$nb,$method_id); if(empty($method_id) or empty($method_id[0])){ if($nb==0){ $this->{$vm_method_name} = 0; } return false; } if ($nb==1) { $this->{$vm_method_name} = $method_id[0]; $this->{$vm_autoSelected_name}=true; //This controlls the variable "automaticSelectedPayment" or "automaticSelectedShipment" which meant before vm3.5, that only one method exists vmdebug('FOUND automatic SELECTED '.$type.' !!',$this->{$vm_method_name}); } else { //This check breaks old plugins, which return 0 instead a correct method id. //There are a lot checks following executing checkConditions, so it should be okey to uncomment that. /*if(!empty($this->{$vm_method_name})){ if(!in_array($this->{$vm_method_name},$method_id)){ $this->{$vm_method_name} = 0; vmdebug('SELECTED Method not among selectables '.$type.' !!',$this->{$vm_method_name},$method_id); } }*/ if(empty($this->{$vm_method_name})){ if(empty($setAutomatic)){ $this->{$vm_method_name} = $method_id[0]; vmdebug('SELECTED automatic method '.$type.' !!',$this->{$vm_method_name}); } else { if($setAutomatic>0){ if(in_array($setAutomatic,$method_id)){ $this->{$vm_method_name} = $setAutomatic; vmdebug('SELECTED by automatic method '.$type.' '.$setAutomatic.'!!',$this->{$vm_method_name}); } else { $this->{$vm_method_name} = 0; vmdebug('SELECTED NOT by automatic method '.$type.' '.$setAutomatic.'!!',$this->{$vm_method_name}); } } } } } VmConfig::$_debug = $d; $this->setCartIntoSession(); return true; } /* * CheckAutomaticSelectedShipment * If only one shipment is available for this amount, then automatically select it * @deprecated * @author Valérie Isaksen */ function CheckAutomaticSelectedShipment() { return $this->checkAutomaticSelectedPlug('shipment'); } /* * CheckAutomaticSelectedPayment * If only one payment is available for this amount, then automatically select it * @deprecated * @author Valérie Isaksen */ function CheckAutomaticSelectedPayment() { return $this->checkAutomaticSelectedPlug('payment'); } /** * Function Description * * @author Max Milbers * @access public * @param array $cart the cart to get the products for * @return array of product objects */ public function getCartPrices($force=false) { if(empty($this->cartPrices) or !$this->_calculated or $force){ $calculator = calculationHelper::getInstance(); $this->pricesCurrency = $calculator->_currencyDisplay->getCurrencyForDisplay(); $calculator->getCheckoutPrices($this); //Fallback for old extensions $this->pricesUnformatted = $this->cartPrices; //We must do this here, otherwise if we have a product more than one time in the cart //it has always the same price foreach($this->products as $k => $product){ $this->products[$k]->prices = &$product->allPrices[$product->selectedPrice]; } $this->_calculated = true; //$this->setCartIntoSession(); } return $this->cartPrices; } function prepareVendor(){ if(empty($this->vendor)){ $vendorModel = VmModel::getModel('vendor'); $this->vendor = $vendorModel->getVendor($this->vendorId); $vendorModel->addImages($this->vendor,1); if (VmConfig::get('enable_content_plugin', 0)) { shopFunctionsF::triggerContentPlugin($this->vendor, 'vendor','vendor_terms_of_service'); } } } static function getProduct( $virtuemart_product_id, $quantity){ $productModel = VmModel::getModel('product'); //We use here the same params as in order model function getOrder to be able to use the cache $productTemp = $productModel->getProduct($virtuemart_product_id, true, false, false,$quantity); if(empty($productTemp->virtuemart_product_id) or empty($productTemp->published)){ vmError('The product is no longer available; cart getProduct is empty','The product is no longer available'); vmTrace('Product empty'); return false; } $productTemp->modificatorSum = null; //Very important! must be cloned, else all products with same id get the same productCustomData due the product cache return clone($productTemp); } function prepareCartData($force=true){ //$this->totalProduct = 0; if(count($this->products) != count($this->cartProductsData) or $this->_productAdded){ $productsModel = VmModel::getModel('product'); $this->totalProduct = 0; $this->productsQuantity = array(); foreach($this->cartProductsData as $k =>&$productdata){ $productdata = (array)$productdata; if(isset($productdata['virtuemart_product_id'])){ if(empty($productdata['virtuemart_product_id']) or empty($productdata['quantity'])){ unset($this->cartProductsData[$k]); continue; } $productdata['quantity'] = (int)$productdata['quantity']; //Important, must not use calculation, would lead to wrong prices, because the full cart is not know yet. $product = VirtueMartCart::getProduct($productdata['virtuemart_product_id'], $productdata['quantity']); if(!$product or ($product->product_discontinued and !VmConfig::get('discontinuedPrdsBrowseable',1))){ vmError('The product is no longer available; prepareCartData virtuemart_product_id is empty','The product is no longer available'); unset($this->cartProductsData[$k]); continue; } $productdata['virtuemart_product_id'] = (int)$productdata['virtuemart_product_id']; $product -> customProductData = $productdata['customProductData']; $product -> quantity = $productdata['quantity']; // No full link because Mail want absolute path and in shop is better relative path $product->url = JRoute::_('index.php?option=com_virtuemart&view=productdetails&virtuemart_product_id='.$product->virtuemart_product_id.'&virtuemart_category_id='.$product->virtuemart_category_id);//JHtml::link($url, $product->product_name); $product->cart_item_id = $k ; if ( VmConfig::get('oncheckout_show_images')){ $productsModel->addImages($product,1); } //$product->customfields = $customFieldsModel->getCustomEmbeddedProductCustomFields($product->allIds,0,1); $enough = $this->checkForQuantities($product,$product -> quantity); if($product->quantity<=0){ unset($this->cartProductsData[$k]); continue; } $this->products[$k] = $product; $this->totalProduct += $product -> quantity; $productdata['quantity'] = $product -> quantity; if(isset($this->productsQuantity[$product->virtuemart_product_id])){ $this->productsQuantity[$product->virtuemart_product_id] += $product -> quantity; } else { $this->productsQuantity[$product->virtuemart_product_id] = $product -> quantity; } $product = null; } else { unset($this->cartProductsData[$k]); vmError('prepareCartData $productdata[virtuemart_product_id] was empty'); } } $this->setCartIntoSession(); } else { } $this->getCartPrices($force); vDispatcher::importVMPlugins('vmpayment'); $returnValues = vDispatcher::trigger('plgVmgetPaymentCurrency', array( $this->virtuemart_paymentmethod_id, &$this->paymentCurrency)); $this->_productAdded = false; self::$_carts[$this->vendorId] = &self::$_cart; return $this->cartData ; } /* * Trigger to place Coupon, payment, shipment advertisement on the cart */ public function getCheckoutAdvertise() { if(!$this->cartAdv){ $this->cartAdv=array(); vDispatcher::importVMPlugins('vmpayment'); $returnValues = vDispatcher::trigger('plgVmOnCheckoutAdvertise', array( $this, &$this->cartAdv)); } return $this->cartAdv; } public function checkForCartQuantities() { $quantities = vRequest::getInt('quantity'); if(empty($quantities)) return true; $updated = false; foreach($quantities as $key=>$quantity){ if (isset($this->cartProductsData[$key]) and !empty($quantity) and !isset($_POST['delete_'.$key])) { if($quantity!=$this->cartProductsData[$key]['quantity']){ $isok = true; $newTotal = $quantity; if (isset($this->products[$key])) { $product = $this->products[$key]; $this->checkForQuantities($product, $newTotal); if ($newTotal !== $quantity) { $quantity = $newTotal; $isok = false; } } $this->cartProductsData[$key]['quantity'] = $quantity; $updated = true; if ($isok) { vmInfo('COM_VIRTUEMART_PRODUCT_UPDATED_SUCCESSFULLY'); } else { } } } else { unset($this->cartProductsData[$key]); vmInfo('COM_VIRTUEMART_PRODUCT_REMOVED_SUCCESSFULLY'); $updated = true; } } $this->setCartIntoSession( false, $updated); return $updated; } /** Checks if the quantity is correct * * @author Max Milbers */ private function checkForQuantities($product, &$quantity=0) { vDispatcher::importVMPlugins('vmcustom'); // return null to proceed with further VM rules // return true to not validate the quantity with OPC or VM // return false to return errorMsg //if to allow to adjust the current quantity $adjustQ = false; $errorMsg = ''; $cart = &$this; $retValues = vDispatcher::trigger('plgVmOnCheckoutCheckStock', array( &$cart, &$product, &$quantity, &$errorMsg, &$adjustQ)); foreach ($retValues as $v) { if ($v === false) { vmInfo($errorMsg,$product->product_name); return false; } if ($v === true) { return true; } } $stockhandle = VmConfig::get('stockhandle_products', false) && $product->product_stockhandle ? $product->product_stockhandle : VmConfig::get('stockhandle','none'); // Check for a valid quantity if (!is_numeric( $quantity)) { $product->errorMsg = vmText::sprintf('COM_VIRTUEMART_CART_ERROR_NO_VALID_QUANTITY', $product->product_name); vmWarn($product->errorMsg); return false; } // Check for negative quantity if ($quantity < 1) { $product->errorMsg = vmText::sprintf('COM_VIRTUEMART_CART_ERROR_NO_VALID_QUANTITY', $product->product_name); vmWarn($product->errorMsg); return false; } $checkForDisable = false; if ($stockhandle!='none' && $stockhandle!='risetime') { $checkForDisable = true; } // Check for the minimum and maximum quantities $min = (int)$product->min_order_level; if ($min != 0 && $quantity < $min){ $quantity = $min; $product->errorMsg = vmText::sprintf('COM_VIRTUEMART_CART_MIN_ORDER', $min, $product->product_name); vmWarn($product->errorMsg); if (!$checkForDisable) return false; } $step = (int)$product->step_order_level; $max = (int)$product->max_order_level; if ($step != 0 && ($quantity%$step)!= 0) { /* stAn - with step quantity we have these options: - we raise it by default to next step - the next step may not be valid against max_order_level (set quantity=0) - so we lower it to previous step - which may not be valid against min_order_level (set quantity=0) - or previous step is smaller than 0 (set quantity=0) stAn get next value - example: q=500, step=3 => 500 - (2) + 3 = 501 */ $quantity = $quantity - ($quantity%$step) + $step; if ((!empty($product->max_order_level)) && ($quantity > (int)$product->max_order_level)) { //get previous step quantity and have it validated by next section: $quantity = $quantity - $step; if ($quantity < 0) $quantity = 0; if ($quantity < (int)$product->min_order_level) { $quantity = 0; } } $product->errorMsg = vmText::sprintf('COM_VIRTUEMART_CART_STEP_ORDER', $step); vmWarn($product->errorMsg); if (!$checkForDisable) return false; /*stAn, next step is larger than max_order_level and previous step is smaller then zero OR smaller then min_order_level*/ if (empty($quantity)) { return false; //stAn - can we really return false for invalid value ? } } if ($max != 0 && $quantity > $max) { $quantity = $max; $product->errorMsg = vmText::sprintf('COM_VIRTUEMART_CART_MAX_ORDER', $max, $product->product_name); vmWarn($product->errorMsg); if (!$checkForDisable) return false; } // Check to see if checking stock quantity if ($checkForDisable) { $productsleft = $product->product_in_stock - $product->product_ordered; if ($quantity > $productsleft ){ vmdebug('my products left '.$productsleft.' and my quantity '.$quantity); if($productsleft>=$min ){ $quantity = $productsleft; $product->errorMsg = vmText::sprintf('COM_VIRTUEMART_CART_PRODUCT_OUT_OF_QUANTITY',$product->product_name,$quantity); vmWarn($product->errorMsg); } else { $quantity = 0; $product->errorMsg = vmText::_('COM_VIRTUEMART_CART_PRODUCT_OUT_OF_STOCK'); vmWarn($product->errorMsg); return false; } } } return true; } // Render the code for Ajax Cart function prepareAjaxData($withProductImages=false, $force = false){ $this->prepareCartData($force); $data = new stdClass(); $data->products = array(); $data->totalProduct = 0; //OSP when prices removed needed to format billTotal for AJAX $currencyDisplay = CurrencyDisplay::getInstance(); foreach ($this->products as $i=>$product){ //Create product URL $url = JRoute::_('index.php?option=com_virtuemart&view=productdetails&virtuemart_product_id='.$product->virtuemart_product_id.'&virtuemart_category_id='.$product->virtuemart_category_id, FALSE); $data->products[$i]['product_name'] = JHtml::link($url, $product->product_name); // custom product fields display for cart //Todo the customProductData should be renamed, because it is not the same customProductData as used elsewhere $data->products[$i]['customProductData'] = VirtueMartModelCustomfields::CustomsFieldCartModDisplay($product); $data->products[$i]['product_sku'] = $product->product_sku; $data->products[$i]['prices'] = $currencyDisplay->priceDisplay( $product->allPrices[$product->selectedPrice]['subtotal']); if($withProductImages and !empty($product->images[0])) $data->products[$i]['image']= $product->images[0]->displayMediaThumb ('', FALSE); // other possible option to use for display $data->products[$i]['subtotal'] = $currencyDisplay->priceDisplay($product->allPrices[$product->selectedPrice]['subtotal']); $data->products[$i]['subtotal_tax_amount'] = $currencyDisplay->priceDisplay($product->allPrices[$product->selectedPrice]['subtotal_tax_amount']); $data->products[$i]['subtotal_discount'] = $currencyDisplay->priceDisplay( $product->allPrices[$product->selectedPrice]['subtotal_discount']); $data->products[$i]['subtotal_with_tax'] = $currencyDisplay->priceDisplay($product->allPrices[$product->selectedPrice]['subtotal_with_tax']); // UPDATE CART / DELETE FROM CART $data->products[$i]['quantity'] = $product->quantity; $data->totalProduct += $product->quantity ; } if(empty($this->cartPrices['billTotal']) or $this->cartPrices['billTotal'] < 0){ $this->cartPrices['billTotal'] = 0.0; } $data->billTotal = $currencyDisplay->priceDisplay( $this->cartPrices['billTotal'] ); $data->billTotal_tax_amount = $currencyDisplay->priceDisplay( $this->cartPrices['taxAmount'] ); $data->billTotal_net = $currencyDisplay->priceDisplay( $this->cartPrices['priceWithoutTax'] ); $data->billTotal_discounted_net = $currencyDisplay->priceDisplay( $this->cartPrices['discountedPriceWithoutTax'] ); //end $data->dataValidated = $this->_dataValidated ; if ($data->totalProduct>1) $data->totalProductTxt = vmText::sprintf('COM_VIRTUEMART_CART_X_PRODUCTS', $data->totalProduct); else if ($data->totalProduct == 1) $data->totalProductTxt = vmText::_('COM_VIRTUEMART_CART_ONE_PRODUCT'); else $data->totalProductTxt = vmText::_('COM_VIRTUEMART_EMPTY_CART'); $taskRoute = ''; $data->linkName = vmText::_('COM_VIRTUEMART_CART_SHOW'); $multixcart = VmConfig::get('multixcart',0); if(!empty($multixcart)){ $taskRoute .= '&virtuemart_vendor_id='.$this->vendorId; } $data->cart_show_link = JRoute::_("index.php?option=com_virtuemart&view=cart".$taskRoute,$this->useSSL); $data->cart_show = ''.$data->linkName.''; $data->billTotal = vmText::sprintf('COM_VIRTUEMART_CART_TOTALP',$data->billTotal); return $data ; } /** * Get the total weight for the order, based on which the proper shipping rate * can be selected. * * @param object $cart Cart object * @return float Total weight for the order */ static public function getCartWeight (VirtueMartCart $cart, $to_weight_unit = 0) { if(empty($to_weight_unit)) $to_weight_unit = VmConfig::get('weight_unit_default','KG'); $weight = 0.0; if(count($cart->products)>0){ foreach ($cart->products as $product) { $weight += (ShopFunctions::convertWeightUnit ($product->product_weight, $product->product_weight_uom, $to_weight_unit) * $product->quantity); } } return $weight; } /** * Get the total Quantity for the order, based on which the proper shipping rate * can be selected. * * @param object $cart Cart object * @return float Total weight for the order */ static public function getCartQuantity (VirtueMartCart $cart) { $qu = 0; //Must not be static! if(count($cart->products)>0 and empty($qu)){ foreach ($cart->products as $product) { $qu += $product->quantity; } } return $qu; } function unsetForDebug(){ foreach($this->products as $product){ $product->unsetForDebug(); } if(!empty($this->user)) $this->user->unsetForDebug(); //unset($this->user->JUser->_db); if(isset($this->vendor)) $this->vendor->unsetForDebug(); } function resetForDebug(){ foreach($this->products as $product){ $product->resetForDebug(); } if(!empty($this->user)) $this->user->resetForDebug(); if(isset($this->vendor)) $this->vendor->resetForDebug(); } }