db is never used in the model ? * @package VirtueMart */ class VirtueMartModelOrders extends VmModel { /** * constructs a VmModel * setMainTable defines the maintable of the model * @author Max Milbers */ function __construct() { parent::__construct(); $this->setMainTable('orders'); $this->addvalidOrderingFieldName(array('order_name','order_email','payment_method','shipment_method','virtuemart_order_id' ) ); $this->setToggleName('paid'); $this->setToggleName('invoice_locked'); $this->populateState(); vDispatcher::importVMPlugins('vmpayment'); self::$searchMap = array( 'name:' => array('_name','username'), 'last_name:' => 'last_name', 'surname:' => 'last_name', 'street:' => 'address_', 'email:' => 'email', 'city:' => 'city', 'zip:' => 'zip', 'order:' => 'order_number', 'invoice:' => 'invoice_number' ); } function populateState () { $type = 'search'; $task = vRequest::getCmd('task',''); $view = vRequest::getCmd('view','orders'); $k= 'com_virtuemart.'.$view.'.'.$task.$type; $ts = vRequest::getString($type, false); $app = JFactory::getApplication(); if($ts===false){ $this->{$type} = $app->getUserState($k, ''); } else { $app->setUserState( $k,$ts); $this->{$type} = $ts; } $this->__state_set = true; } /** * This function gets the orderId, for anonymous users * @author Max Milbers */ public function getOrderIdByOrderPass($orderNumber,$orderPass){ $db = JFactory::getDBO(); $q = 'SELECT `virtuemart_order_id` FROM `#__virtuemart_orders` WHERE `order_pass`="'.$db->escape(trim($orderPass)).'" AND `order_number`="'.$db->escape(trim($orderNumber)).'"'; $db->setQuery($q); $orderId = $db->loadResult(); if(empty($orderId)){ vmdebug('getOrderIdByOrderPass no Order found $orderNumber = '.$orderNumber.' $orderPass = '.$orderPass.' $q = '.$q); } else { vmdebug('getOrderIdByOrderPass Order found $orderNumber = '.$orderNumber.' $orderPass = '.$orderPass.' id '.$orderId); } return $orderId; } /** * This function gets the orderId, for payment response * author Valerie Isaksen */ public static function getOrderIdByOrderNumber($orderNumber){ $db = JFactory::getDBO(); $q = 'SELECT `virtuemart_order_id` FROM `#__virtuemart_orders` WHERE `order_number`="'.$db->escape($orderNumber).'"'; $db->setQuery($q); $orderId = $db->loadResult(); return $orderId; } /** * This function gets the secured order Number * @param $virtuemart_order_id * @return string/null */ public function getOrderNumber($virtuemart_order_id){ $db = JFactory::getDBO(); $q = 'SELECT `order_number` FROM `#__virtuemart_orders` WHERE virtuemart_order_id="'.(int)$virtuemart_order_id.'" '; $db->setQuery($q); $OrderNumber = $db->loadResult(); return $OrderNumber; } /** * Get next orderId * @param $order_id * @param string $direction * @return int|mixed|null */ public function getNextOrderId($order_id, $direction ='DESC') { if ($direction == 'ASC') { $arrow ='>'; } else { $arrow ='<'; } $db = JFactory::getDBO(); $q = 'SELECT `virtuemart_order_id` FROM `#__virtuemart_orders` WHERE `virtuemart_order_id`'.$arrow.(int)$order_id; $q.= ' ORDER BY `virtuemart_order_id` '.$direction ; $db->setQuery($q); if ($oderId = $db->loadResult()) { return $oderId ; } return 0 ; } /** * This is a proxy function to return an order safely, we may set the getOrder function to private * Maybe the right place would be the controller, cause there are vRequests in it. But for a fast solution, * still better than to have it 3-4 times in the view.html.php of the views. * @author Max Milbers * * @return array */ public function getMyOrderDetails($orderID = 0, $orderNumber = false, $orderPass = false, $vmConf=true) { if (VmConfig::get('ordertracking', 'guests') == 'none' and !vmAccess::manager('orders')) { return false; } $virtuemart_order_id = vRequest::getInt('virtuemart_order_id', $orderID); $orderNumber = trim(vRequest::getString('order_number', $orderNumber)); $sess = JFactory::getSession(); if (empty($orderNumber)) { $h = $virtuemart_order_id; } else { $h = $orderNumber; } $tries = $sess->get('getOrderDetails.'.$h,0); if($tries>6){ vmDebug ('Too many tries, Invalid order_number/password '.vmText::_('COM_VIRTUEMART_RESTRICTED_ACCESS')); vmError ('Too many tries, Invalid order_number/password guest '.$orderNumber.' '.$orderPass , 'COM_VIRTUEMART_RESTRICTED_ACCESS'); return false; } else { $tries++; $sess->set('getOrderDetails.'.$h,$tries); } $_currentUser = JFactory::getUser(); $cuid = $_currentUser->get('id'); //Extra check, when a user is logged in, else we use the guest method if(!empty($cuid)){ if (!$virtuemart_order_id and $orderNumber) { $virtuemart_order_id = VirtueMartModelOrders::getOrderIdByOrderNumber($orderNumber); } if(!empty($virtuemart_order_id)){ $orderDetails = $this->getOrder($virtuemart_order_id); if($orderDetails['details']['BT']->virtuemart_user_id == $cuid or vmAccess::manager('orders')) { $sess->set('getOrderDetails.'.$h,0); return $orderDetails; } } } else if($vmConf and VmConfig::get('ordertracking','guests') == 'registered' and empty($cuid)){ return true; } if(!empty( $orderNumber )){ if($vmConf and VmConfig::get('ordertracking','guests') != 'guestlink' and VmConfig::get('ordertracking','guests') != 'guests'){ return false; } $orderPass = trim(vRequest::getString( 'order_pass', $orderPass )); if( empty( $orderPass )) { return false; } else { $orderId = $this->getOrderIdByOrderPass( $orderNumber, $orderPass ); if($orderId) { if(!$vmConf or (VmConfig::get('ordertracking','guests') == 'guestlink' or vmAccess::manager('orders'))){ $sess->set('getOrderDetails.'.$h,0); return $this->getOrder( $orderId ); } //Guest case else { $o = $this->getOrder( $orderId ); if(empty( $o['details']['BT']->virtuemart_user_id ) ) { $sess->set('getOrderDetails.'.$h,0); return $o; } else { return false; } } } } } return false; } public $order = null; /** * Load a single order, Attention, this function is not protected! Do the right manangment before, to be certain * we suggest to use getMyOrderDetails */ public function getOrder($virtuemart_order_id){ //sanitize id $virtuemart_order_id = (int)$virtuemart_order_id; $db = JFactory::getDBO(); $order = array(); // Get the order details $q = "SELECT o.*, o.created_on as order_created, o.modified_on as order_modified, o.modified_by as order_modified_by, u.*, s.order_status_code, s.order_status_color, s.order_status_name, s.order_status_description, s.order_stock_handle, s.ordering FROM #__virtuemart_orders o LEFT JOIN #__virtuemart_orderstates s ON s.order_status_code = o.order_status LEFT JOIN #__virtuemart_order_userinfos u ON u.virtuemart_order_id = o.virtuemart_order_id WHERE o.virtuemart_order_id=".$virtuemart_order_id; $db->setQuery($q); $order['details'] = $db->loadObjectList('address_type'); if($order['details'] and isset($order['details']['BT'])){ $order["details"]["BT"]->created_on = &$order["details"]["BT"]->order_created; $order["details"]["BT"]->modified_on = &$order["details"]["BT"]->order_modified; $order["details"]["BT"]->modified_by = &$order["details"]["BT"]->order_modified_by; $concat = array(); if(!empty($order['details']['BT']->company)) $concat[]= $order['details']['BT']->company; if(!empty($order['details']['BT']->first_name)) $concat[]= $order['details']['BT']->first_name; if(!empty($order['details']['BT']->middle_name)) $concat[]= $order['details']['BT']->middle_name; if(!empty($order['details']['BT']->last_name)) $concat[]= $order['details']['BT']->last_name; $order['details']['BT']->order_name = ''; foreach($concat as $c){ $order['details']['BT']->order_name .= trim($c).' '; } $order['details']['BT']->order_name = trim(vRequest::vmSpecialChars(strip_tags(htmlspecialchars_decode($order['details']['BT']->order_name)))); if(isset($order['details']['ST'])){ $order['details']['has_ST'] = true; } else { $order['details']['has_ST'] = false; $order['details']['ST'] =&$order['details']['BT']; } $order['details']['BT']->paid = floatval($order['details']['BT']->paid); } // Get the order history $q = "SELECT * FROM #__virtuemart_order_histories WHERE virtuemart_order_id=".$virtuemart_order_id." ORDER BY virtuemart_order_history_id ASC"; $db->setQuery($q); $order['history'] = $db->loadObjectList(); // Get the order items $q = 'SELECT virtuemart_order_item_id, product_quantity, order_item_name, order_item_sku, i.virtuemart_product_id, product_item_price, product_final_price, product_basePriceWithTax, product_discountedPriceWithoutTax, product_priceWithoutTax, product_subtotal_with_tax, product_subtotal_discount, product_tax, product_attribute, order_status, paid, intnotes, virtuemart_category_id FROM #__virtuemart_order_items i LEFT JOIN #__virtuemart_products p ON p.virtuemart_product_id = i.virtuemart_product_id LEFT JOIN #__virtuemart_product_categories c ON p.virtuemart_product_id = c.virtuemart_product_id WHERE `virtuemart_order_id`="'.$virtuemart_order_id.'" group by `virtuemart_order_item_id`'; $orderBy = VmConfig::get('order_item_ordering','virtuemart_order_item_id'); if (!empty ( $orderBy)) { $orderingDir = VmConfig::get('order_item_ordering_dir','ASC'); $q .= ' ORDER BY `'.$orderBy.'` ' . $orderingDir; } //group by `virtuemart_order_id`'; Why ever we added this, it makes trouble, only one order item is shown then. // without group by we get the product 3 times, when it is in 3 categories and similar, so we need a group by //lets try group by `virtuemart_order_item_id` $db->setQuery($q); $order['items'] = $db->loadObjectList(); $customfieldModel = VmModel::getModel('customfields'); $pModel = VmModel::getModel('product'); foreach($order['items'] as $p=>$item){ $ids = array(); $product = $pModel->getProduct($item->virtuemart_product_id, true, false, false); if($product){ $pvar = get_object_vars($product); foreach ( $pvar as $k => $v) { if ( strpos ($k, '_') === 0){ continue; } if (!isset($item->{$k}) and property_exists($product, $k)) { $item->{$k} = $v; } } } $item->paid = floatval($item->paid); $order['items'][$p] = $item; } // Get the order items $q = "SELECT * FROM #__virtuemart_order_calc_rules AS z WHERE virtuemart_order_id=".$virtuemart_order_id; $db->setQuery($q); $order['calc_rules'] = $db->loadObjectList(); return $order; } public function getOrderCount($uid){ $db = JFactory::getDBO(); $q = 'SELECT COUNT(virtuemart_user_id) FROM #__virtuemart_orders WHERE virtuemart_user_id = "'.$uid.'" '; $db->setQuery($q); $r = $db->loadResult(); return $r; } public $virtuemart_vendor_id = false; /** * Select the products to list on the product list page * @param $uid integer Optional user ID to get the orders of a single user * @param $_ignorePagination boolean If true, ignore the Joomla pagination (for embedded use, default false) */ public function getOrdersList($uid = 0, $noLimit = false) { $result = array(); $used = vDispatcher::trigger('plgVmMySortSearchListOrdersQuery', array( &$result, $this->search, $uid, $noLimit )); if($used){ foreach ($used as $ret) { if ($ret === true) { return $result; //if plugin returns true, return it's values from the result } } } // vmdebug('getOrdersList'); $tUserInfos = $this->getTable('userinfos'); $this->_noLimit = $noLimit; $concat = array(); if(property_exists($tUserInfos,'company')) $concat[]= 'u.company'; if(property_exists($tUserInfos,'first_name')) $concat[]= 'u.first_name'; if(property_exists($tUserInfos,'middle_name')) $concat[]= 'u.middle_name'; if(property_exists($tUserInfos,'last_name')) $concat[]= 'u.last_name'; if(!empty($concat)){ $concatStr = "CONCAT_WS(' ',".implode(',',$concat).")"; } else { $concatStr = 'o.order_number'; } // quorvia added phone, zip, city and shipping details and ST data $select = " o.*, ".$concatStr." AS order_name " .',u.email as order_email, pm.payment_name AS payment_method, sm.shipment_name AS shipment_method, u.company AS company, u.city AS city, u.zip AS zip, u.phone_1 AS phone, st.address_type AS st_type, st.company AS st_company, st.city AS st_city, st.zip AS st_zip, u.customer_note AS customer_note'; $where = array(); $byOrderItem = false; $groupBy = ''; if(empty($uid)){ if(VmConfig::get('multix','none')!='none'){ if(vmAccess::manager('managevendors')){ $virtuemart_vendor_id = vRequest::getInt('virtuemart_vendor_id',$this->virtuemart_vendor_id/*vmAccess::isSuperVendor()*/); } else if( vmAccess::manager('orders')){ $virtuemart_vendor_id = vmAccess::isSuperVendor(); } else { $virtuemart_vendor_id = false; } if($virtuemart_vendor_id){ if(VmConfig::get('allowVendorsSeeMainOrder', true) and empty(VmConfig::get('multixcart',0))){ $byOrderItem = true; $tbpre = 'oi'; $groupBy = 'GROUP BY virtuemart_order_id'; } else { $tbpre = 'o'; } $where[]= ' '.$tbpre.'.virtuemart_vendor_id = ' . (int)$virtuemart_vendor_id.' '; } } if(!vmAccess::manager('orders')){ //A normal user is only allowed to see its own orders, we map $uid to the user id $user = JFactory::getUser(); $uid = (int)$user->id; if(!empty($uid)){ $where[]= ' u.virtuemart_user_id = ' . (int)$uid.' '; } } } else { $where[]= ' u.virtuemart_user_id = ' . (int)$uid.' '; } $from = $this->getOrdersListQuery($byOrderItem); if ($this->search){ $db = JFactory::getDBO(); $this->search = '"%' . $db->escape( $this->search, true ) . '%"' ; $this->search = str_replace(' ','%',$this->search); $searchFields = array(); $searchFields[] = 'u.first_name'; //$searchFields[] = 'u.middle_name'; $searchFields[] = 'u.last_name'; $searchFields[] = 'o.order_number'; $searchFields[] = 'u.company'; $searchFields[] = 'u.email'; $searchFields[] = 'u.phone_1'; $searchFields[] = 'u.address_1'; $searchFields[] = 'u.city'; $searchFields[] = 'u.zip'; //quorvia added ST data searches and virtuemart_order_id and order total $searchFields[] = 'o.virtuemart_order_id'; $searchFields[] = 'round(o.order_total,2)'; $searchFields[] = 'u.customer_note'; $searchFields[] = 'o.order_note'; $searchFields[] = 'st.last_name'; $searchFields[] = 'st.company'; $searchFields[] = 'st.city'; $searchFields[] = 'st.zip'; $where[] = implode (' LIKE '.$this->search.' OR ', $searchFields) . ' LIKE '.$this->search.' '; //$where[] = ' ( u.first_name LIKE '.$search.' OR u.middle_name LIKE '.$search.' OR u.last_name LIKE '.$search.' OR `order_number` LIKE '.$search.')'; } $order_status_code = vRequest::getString('order_status_code', false); if ($order_status_code and $order_status_code!=-1){ $where[] = ' o.order_status = "'.$order_status_code.'" '; } if (count ($where) > 0) { $whereString = ' WHERE (' . implode (' AND ', $where) . ') '; } else { $whereString = ''; } if ( vRequest::getCmd('view') == 'orders') { $ordering = $this->_getOrdering(); } else { $ordering = ' order by o.modified_on DESC'; } $this->_data = $this->exeSortSearchListQuery(0,$select,$from,$whereString,$groupBy,$ordering); if($this->_data){ foreach($this->_data as $k=>$d){ $this->_data[$k]->order_name = vRequest::vmSpecialChars(strip_tags(htmlspecialchars_decode($d->order_name))); } } return $this->_data ; } /** * List of tables to include for the product query */ public function getOrdersListQuery($byOrderItem = false) { $q = ' FROM #__virtuemart_orders as o LEFT JOIN #__virtuemart_order_userinfos as u ON u.virtuemart_order_id = o.virtuemart_order_id AND u.address_type="BT" LEFT JOIN #__virtuemart_order_userinfos as st ON st.virtuemart_order_id = o.virtuemart_order_id AND st.address_type="ST" '; if($byOrderItem){ $q .= ' LEFT JOIN #__virtuemart_order_items as oi ON o.virtuemart_order_id = oi.virtuemart_order_id '; } $q .= ' LEFT JOIN #__virtuemart_paymentmethods_'.VmConfig::$vmlang.' as pm ON o.virtuemart_paymentmethod_id = pm.virtuemart_paymentmethod_id LEFT JOIN #__virtuemart_shipmentmethods_'.VmConfig::$vmlang.' as sm ON o.virtuemart_shipmentmethod_id = sm.virtuemart_shipmentmethod_id'; return $q; } /** * Update an order item status * $vatTax was $orderUpdate boolean, keeps now the vattaxes * @author Max Milbers * @author Ondřej Spilka - used for item edit also * @author Maik Künnemann */ public function updateSingleItem($virtuemart_order_item_id, &$orderdata, $orderUpdate = false, &$itemTaxes = array(), $orderUserId=0) { $virtuemart_order_item_id = (int)$virtuemart_order_item_id; //vmdebug('updateSingleItem',$virtuemart_order_item_id,$orderdata); $table = $this->getTable('order_items'); $oldQuantity = 0; if(!empty($virtuemart_order_item_id)){ $table->load($virtuemart_order_item_id); $oldOrderStatus = $table->order_status; $oldQuantity = $table->product_quantity; } if(empty($oldOrderStatus)){ $oldOrderStatus = $orderdata->current_order_status; if($orderUpdate and empty($oldOrderStatus)){ $oldOrderStatus = 'P'; } } $dataT = $table->getProperties();//get_object_vars($table); $orderdatacopy = $orderdata; $data = array_merge($dataT,(array)$orderdatacopy); $this->_currencyDisplay = CurrencyDisplay::getInstance(); $rounding = VmConfig::get('roundindig',true)? 5:$this->_currencyDisplay->_priceConfig['salesPrice'][1]; $date = JFactory::getDate(); $today = $date->toSQL(); //$vatTaxes = array(); if ( $orderUpdate and !empty($data['virtuemart_order_item_id'])) { $db = JFactory::getDBO(); if(empty($virtuemart_order_item_id) and !empty($data['order_item_sku'])){ $q = 'SELECT `virtuemart_product_id` FROM #__virtuemart_products WHERE product_sku ="'.$data['order_item_sku'].'"'; $db->setQuery($q); $data['virtuemart_product_id'] = $db->loadResult(); vmdebug('vm product id by sku',$data['virtuemart_product_id']); } if(!empty($data['virtuemart_product_id']) and empty($data['order_item_name'])){ //vmEcho::$echoDebug = 1; $uM = VmModel::getModel('shoppergroup'); if(empty($orderUserId)){ $std_grp = $uM->getDefault(0,true); $orderuser_shoppergroups = array($std_grp->virtuemart_shoppergroup_id); vmdebug('$orderuser_shoppergroups guest',$orderuser_shoppergroups); } else { $xrefTable = $this->getTable('vmuser_shoppergroups'); $orderuser_shoppergroups = $xrefTable->load($orderUserId); vmdebug('$orderuser_shoppergroups registered',$orderuser_shoppergroups); $pseudUser = new stdClass(); $pseudUser->guest = 0; $uM->appendShopperGroups($orderuser_shoppergroups,$pseudUser); } $pM = VmModel::getModel('product'); $p = $pM->getProduct($data['virtuemart_product_id'], true, true, true, $data['product_quantity'],$orderuser_shoppergroups); if(empty($data['product_item_price'])){ $data['product_item_price'] = $p->prices['basePrice']; vmdebug('vm product set price',$p->prices,$data['product_item_price']); } if(empty($data['order_item_sku'])){ $data['order_item_sku'] = $p->product_sku; } if(empty($data['order_item_name'])){ $data['order_item_name'] = $p->product_name; } } $taxCalcValue = 0; $daTax = 'notset'; foreach($itemTaxes as $calc_kind=>$t) { foreach($t as $virtuemart_calc_id=>$tax) { if($tax->calc_kind=='VatTax' or $tax->calc_kind=='Tax'){ $vat = &$tax; $taxCalcValue += $vat->calc_value; //vmdebug('Vat set, but here is the Nadelöhr ',$vat); } else if($tax->calc_kind=='DATax'){ $daTax = true; } else if($tax->calc_kind=='DBTax'){ $daTax = false; continue; } } } //When the product has no discount //Todo, Disabled, it is imho better to add a dropdown for rules or to enter the value manually /*if($daTax == 'notset'){ $daTax = VmConfig::get('taxafterdiscount',$daTax); if($daTax == 'notset'){ static $fallbackCached = null; if(isset($fallback)){ $daTax = $fallbackCached; } else { $db = JFactory::getDbo(); $sql = $sql = 'SELECT COUNT(*) FROM `#__virtuemart_calcs` WHERE `calc_kind` = "DATax" '; $db->setQuery($sql); $r = $db->loadResult(); if($r>0){ $daTax = true; } else { $daTax = false; } $fallbackCached = $daTax; } } }*/ $withTax = true; $overwriteDiscount = false; if(empty($data['product_subtotal_discount']) and $data['product_subtotal_discount'] === '' ){ $overwriteDiscount = true; vmdebug('Set $overwriteDiscount '.$data['product_subtotal_discount']); } if(!empty($data['calculate_product_tax'])) { $data = self::calculateRow($data, $taxCalcValue, $rounding, $daTax, $withTax, $overwriteDiscount); //vmdebug('updateSingleItem $taxCalcValue',$taxCalcValue,$data); if($vat->calc_amount!=$data['product_tax']){ $db = JFactory::getDbo(); $q = 'UPDATE `#__virtuemart_order_calc_rules` SET `calc_amount`='.$data['product_tax'].' WHERE `virtuemart_order_id`='.$data['virtuemart_order_id'].' AND `virtuemart_order_item_id`='.$data['virtuemart_order_item_id'].' ;'; $db->setQuery($q); $db->execute(); if(!empty($itemTaxes['VatTax'] and count($itemTaxes['VatTax'])==1)){ reset($itemTaxes['VatTax']); $key = key($itemTaxes['VatTax']); $itemTaxes['VatTax'][$key]->calc_amount = $data['product_tax']; vmdebug('$itemTaxes ',$itemTaxes); } } } } //if(empty($data['virtuemart_vendor_id']) and !empty($table->virtuemart_vendor_id)){ $data['virtuemart_vendor_id'] = $table->virtuemart_vendor_id; //} $table->bindChecknStore($data); if(empty($virtuemart_order_item_id) and !empty($table->virtuemart_order_item_id)){ $virtuemart_order_item_id = $table->virtuemart_order_item_id; } //store history if($orderUpdate){ $table->emptyCache(); $table->load($virtuemart_order_item_id); //vDispatcher::importVMPlugins('vmcustom'); $results = vDispatcher::trigger('plgVmOnUpdateSingleItem', array(&$table, &$orderdata)); if($dataT['oi_hash']!=$table->oi_hash){ if(empty($dataT['virtuemart_order_item_id'])){ $dataT['action'] = 'new'; if(!empty($virtuemart_order_item_id)){ $dataT['virtuemart_order_item_id'] = $virtuemart_order_item_id; } $props = $table->getProperties(); foreach($props as $k=>$v){ if(empty($dataT[$k])){ $dataT[$k] = $v; } } } $tableHist = $this->getTable('order_item_histories'); $tableHist->bindChecknStore($dataT); } } if(!empty($oldQuantity) and $oldQuantity!=$table->product_quantity){ $this->handleStockAfterStatusChangedPerProduct($oldOrderStatus, $oldOrderStatus, $table, $oldQuantity); } $this->handleStockAfterStatusChangedPerProduct($orderdata->order_status, $oldOrderStatus, $table,$table->product_quantity); foreach($orderdata as $key=>$val){ if($key=='virtuemart_vendor_id') continue; //Todo add multvendor handling if(isset($table->{$key})) $orderdata->{$key} = $table->{$key}; } return $table; } function calculateRow($data, $taxCalcValue, $rounding, $daTax = true, $withTax = true, $overrideDiscount = false){ $quantity = $data['product_quantity']; $data['product_final_price'] = doubleval($data['product_final_price']); $data['product_subtotal_discount'] = doubleval($data['product_subtotal_discount']); $data['product_basePriceWithTax'] = doubleval($data['product_basePriceWithTax']); $data['product_item_price'] = doubleval($data['product_item_price']); $taxValue = doubleval($taxCalcValue); if(!$withTax){ $data['product_tax'] = 0.0; $taxValue = 0.0; } if(empty($data['product_subtotal_discount'])){ $data['product_subtotal_discount'] = 0.0; } else { $itemDiscount = $data['product_subtotal_discount']; if($itemDiscount<0.0){ $itemDiscount = $itemDiscount * (-1); } if($daTax and VirtueMartModelOrders::isNotEmptyDec($data,'product_basePriceWithTax') and VirtueMartModelOrders::isNotEmptyDec($data,'product_final_price')){ $itemDiscount = $data['product_basePriceWithTax'] - $data['product_final_price']; } else if(!$daTax and VirtueMartModelOrders::isEmptyDec($data,'product_subtotal_discount') and VirtueMartModelOrders::isNotEmptyDec($data,'product_final_price') and VirtueMartModelOrders::isNotEmptyDec($data,'product_item_price')){ $itemDiscount = round($data['product_item_price'] - $data['product_final_price'] + $data['product_final_price'] * $taxValue/(100 + $taxValue), $rounding); } else { $itemDiscount = $itemDiscount/$quantity; } } $roundIntern = 5; if(VirtueMartModelOrders::isNotEmptyDec($data,'product_basePriceWithTax') and VirtueMartModelOrders::isEmptyDec($data, 'product_item_price') and VirtueMartModelOrders::isEmptyDec($data,'product_final_price')){ $data['product_item_price'] = doubleval($data['product_basePriceWithTax']) * (1 - $taxCalcValue / ($taxCalcValue + 100)); $data['product_item_price'] = round($data['product_item_price'], $roundIntern); } if(VirtueMartModelOrders::isNotEmptyDec($data,'product_item_price')){ $data['product_basePriceWithTax'] = round( doubleval($data['product_item_price']) * (1 + $taxValue/100.0), $rounding ); if($daTax){ if($overrideDiscount and VirtueMartModelOrders::isEmptyDec($data,'product_subtotal_discount') and VirtueMartModelOrders::isNotEmptyDec($data,'product_final_price')){ $itemDiscount = $data['product_basePriceWithTax'] - doubleval($data['product_final_price']); } else { $data['product_final_price'] = $data['product_basePriceWithTax'] - $itemDiscount; } } else { if($overrideDiscount and VirtueMartModelOrders::isEmptyDec($data,'product_subtotal_discount') and VirtueMartModelOrders::isNotEmptyDec($data,'product_final_price')){ $itemDiscount = round($data['product_item_price'] - $data['product_final_price'] + $data['product_final_price'] * $taxValue/(100 + $taxValue), $rounding); } else { $data['product_final_price'] = round( ($data['product_item_price'] - $itemDiscount) * ((100 + $taxValue)/100.0) , $rounding); } } } else if (VirtueMartModelOrders::isNotEmptyDec($data,'product_final_price')){ if($daTax){ $data['product_item_price'] = round( ($data['product_final_price'] + $itemDiscount) * (1 - $taxValue / ($taxValue + 100)), $roundIntern ) ; $data['product_basePriceWithTax'] = round($data['product_item_price'] * (1 + $taxCalcValue/100.0), $rounding ); } else { $data['product_item_price'] = round( $data['product_final_price'] * (1 - $taxValue / ($taxValue + 100)) + $itemDiscount, $roundIntern ); $data['product_basePriceWithTax'] = round( $data['product_item_price'] * (1 + $taxValue/100.0), $rounding ); } } else { vmdebug('Missing case'); } if($withTax){ $data['product_tax'] = round($data['product_final_price'], $rounding) * $taxCalcValue / ($taxCalcValue + 100); } else { //Todo why we should display this here with tax, if there isnt any? $data['product_basePriceWithTax'] = round( $data['product_item_price'] * (1 + $taxCalcValue/100.0), $rounding ); } $data['product_tax'] = round($data['product_tax'], $roundIntern); $data['product_discountedPriceWithoutTax'] = $data['product_final_price'] - ($data['product_tax']); if($daTax){ $data['product_priceWithoutTax'] = $data['product_final_price'] - $data['product_tax'] + $itemDiscount; } else { $data['product_priceWithoutTax'] = $data['product_final_price'] - $data['product_tax']; } //$data['product_subtotal_discount'] = (round($orderdata->product_final_price, $rounding) - round($data['product_basePriceWithTax'], $rounding)) * $orderdata->product_quantity; $data['product_subtotal_with_tax'] = round($data['product_final_price'], $rounding) * round((float)$data['product_quantity'],3); if($data['product_subtotal_discount']<0.0){ $itemDiscount = $itemDiscount * (-1); } //if($overrideDiscount){ if($daTax and VirtueMartModelOrders::isNotEmptyDec($data,'product_basePriceWithTax') and VirtueMartModelOrders::isNotEmptyDec($data,'product_final_price')){ $itemDiscount = $data['product_basePriceWithTax'] - $data['product_final_price']; } else if(!$daTax and VirtueMartModelOrders::isEmptyDec($data,'product_subtotal_discount') and VirtueMartModelOrders::isNotEmptyDec($data,'product_final_price')){ $itemDiscount = round($data['product_item_price'] - $data['product_final_price'] + $data['product_final_price'] * $taxValue/(100 + $taxValue), $rounding); } //} $data['product_subtotal_discount'] = $quantity * $itemDiscount; //vmdebug('my prices',$data); return $data; } function toggle($field,$val = NULL, $cidname = 0,$tablename = 0, $view = false ) { if($view and !vmAccess::manager($view.'.edit.state')){ return false; } $ok = true; if (!in_array($field, $this->_togglesName)) { vmdebug('vmModel function toggle, field '.$field.' is not in white list'); return false ; } if($tablename === 0) $tablename = $this->_maintablename; if($cidname === 0) $cidname = $this->_cidName; $table = $this->getTable($tablename); $ids = vRequest::getInt( $cidname, vRequest::getInt('cid', array() ) ); vmdebug('Toggle paid $ids',$ids); foreach($ids as $id){ $table->load( (int)$id ); if($field == 'paid'){ $toPay = $table->order_total; $order = $this->getOrder($id); //vmdebug('order model toggle '.$val,$table->paid,$table->order_total, $order); foreach ($order['items'] as $id => $item) { $os_trigger_refunds = VmConfig::get('os_trigger_refunds', array('R')); if(in_array($item->order_status,$os_trigger_refunds)){ //$ok = false; //VmInfo('Cannot set order to paid/unpaid, because there are refunded items. Please check the order manually '.$id); $toPay -= $item->product_subtotal_with_tax; } } $currency = CurrencyDisplay::getInstance(); $unequal = (int)$currency->truncate($toPay-$table->paid); vmdebug('Toggle paid ',$table->paid,$toPay,$toPay-$table->paid,$unequal); if (empty($val)){ if(!empty($table->paid) and $unequal){ $ok = false; VmInfo('Cannot set order to unpaid, paid = '.$table->paid.', but order total = '.$table->order_total.'. Please check the order manually '.$id); } else { $table->paid = 0.00; $table->store(); } } else { if(empty($table->paid) ){ $table->paid = $toPay; $table->store(); } else if($unequal){ $ok = false; VmInfo('Cannot set order to paid, paid = '.$table->paid.', but order total = '.$toPay.'. Please check the order manually '.$id); } } } else { // quorvia force toggling to invoice unlocked regardless if (!empty(VmConfig::get('unlockInvoices',false)) ) { if($field == "invoice_locked") { $val = '0'; } } if (!$table->toggle($field, $val)) { vmError(get_class( $this ).'::toggle '.$id); $ok = false; } } } return $ok; } public static function isEmptyDec($d,$n){ return (boolean) (empty($d[$n]) or $d[$n]==0); } public static function isNotEmptyDec($d,$n){ return (boolean) (isset($d[$n]) and $d[$n]!=0); } public function updateBill($virtuemart_order_id, /*$vattax,*/ $order_rules = false){ $this->_currencyDisplay = CurrencyDisplay::getInstance(); $rounding = VmConfig::get('roundindig',true)? 5:$this->_currencyDisplay->_priceConfig['salesPrice'][1]; //OSP update cartRules/shipment/payment //it would seem strange this is via item edit //but in general, shipment and payment would be tractated as another items of the order //in datas they are not, bu okay we have it here and functional //moreover we can compute all aggregate values here via one aggregate SQL if (!empty( $virtuemart_order_id)) { $db = JFactory::getDBO(); $ordid = $virtuemart_order_id; //cartRules, these are just plain values! $bill_rules = vRequest::getVar('calc_rules',array()); $calculate_billTaxAmount = vRequest::getInt('calculate_billTaxAmount',0); //$calc_rules_amount = 0; $calc_rules_discount_amount = 0.0; $calc_rules_tax_amount = 0.0; $calc_rules_vattax_amount = 0.0; vmdebug('$calculate_billTaxAmount $bill_rules',$calculate_billTaxAmount,$bill_rules); /* if(!empty($bill_rules)) { foreach($bill_rules as $calc_kind => $calcs) { foreach($calcs as $virtuemart_order_calc_rule_id => $calc_amount) { if($calculate_billTaxAmount){ if(!isset($order_rules[$virtuemart_calc_id])) continue; $calc_amount = $order_rules[$virtuemart_calc_id]; } else { $calc_amount = $calc_rule->calc_amount; } if ($calc_kind == 'DBTaxRulesBill' || $calc_kind == 'DATaxRulesBill') { $calc_rules_discount_amount += $calc_amount; } else if ($calc_kind == 'taxRulesBill') { $calc_rules_tax_amount += $calc_amount; } //else if ($calc_kind == 'VatTax') { // $calc_rules_vattax_amount += $calc_amount; //} } } } */ /*vmdebug('updateBill', $taxes); if($taxes){ $calc_rules = array_merge($calc_rules,$taxes); }*/ //vmdebug('updateBill', $vattax, $calc_rules); if(!empty($order_rules)) { //foreach($order_rules as $calc_kind => $calcs) { //foreach($calcs as $virtuemart_calc_id => $calc_rule) { foreach($order_rules as $calc) { /*if($calculate_billTaxAmount and isset($calc->subTotal)){ //if(!isset($vattax[$virtuemart_calc_id])) continue; //$calc_amount = $vattax[$virtuemart_calc_id]; $calc_amount = $calc->subTotal; } else {*/ //$calc_amount = $calc->calc_amount; //}*/ if(!isset($calc->product_quantity)) $calc->product_quantity = 1; if ($calc->calc_kind == 'DBTaxRulesBill' || $calc->calc_kind == 'DATaxRulesBill') { $calc_rules_discount_amount += $calc->calc_amount; } else if ($calc->calc_kind == 'taxRulesBill' or $calc->calc_kind == 'Tax') { $calc_rules_tax_amount += $calc->calc_amount; } else if ( $calc->calc_kind == 'Tax') { $calc_rules_tax_amount += $calc->calc_amount * $calc->product_quantity; } else if ($calc->calc_kind == 'VatTax') { $calc_rules_vattax_amount += $calc->calc_amount /* $calc->product_quantity*/; } } //} } $date = JFactory::getDate(); $today = $date->toSQL(); vmdebug('Updated order $calculate_billTaxAmount ',$calculate_billTaxAmount); if(empty($calculate_billTaxAmount)){ //shipment $os = vRequest::getString('order_shipment'); $ost = vRequest::getString('order_shipment_tax'); if ( $os!="" ) { $sql = 'UPDATE `#__virtuemart_orders` SET `order_shipment`="'.$os.'",`order_shipment_tax`="'.$ost.'", `modified_on` = "'.$today.'" WHERE `virtuemart_order_id`="'.$ordid.'"'; $db->setQuery($sql); if ($db->execute() === false) { vmError('updateSingleItem Error updating order_shipment '.$sql); } vmdebug('Updated order shipment ',$sql); } //payment $op = vRequest::getString('order_payment'); $opt = vRequest::getString('order_payment_tax'); if ( $op!="" ) { $sql = 'UPDATE `#__virtuemart_orders` SET `order_payment`="'.$op.'",`order_payment_tax`="'.$opt.'", `modified_on` = "'.$today.'" WHERE `virtuemart_order_id`="'.$ordid.'"'; $db->setQuery($sql); if ($db->execute() === false) { vmError('updateSingleItem Error updating order payment'.$sql); } vmdebug('Updated order payment ',$sql); } } vmdebug('updateBill $calc_rules_amounts',$calc_rules_vattax_amount, $calc_rules_tax_amount, $calc_rules_discount_amount); //Changing the tax it can happen, that we update values, which are used to calculate other values. So we just update twice //for($i=0;$i<2;$i++){ $sql = 'UPDATE `#__virtuemart_orders` SET '. '`order_discountAmount`=(SELECT sum(product_subtotal_discount) FROM #__virtuemart_order_items where `virtuemart_order_id`='.$ordid.'), `order_billDiscountAmount`=`order_discountAmount`+'.$calc_rules_discount_amount.', `order_salesPrice`=(SELECT sum(product_final_price*product_quantity) FROM #__virtuemart_order_items where `virtuemart_order_id`='.$ordid.'), `order_tax`=(SELECT sum( product_tax*product_quantity) FROM #__virtuemart_order_items where `virtuemart_order_id`='.$ordid.'), `order_subtotal`=(SELECT sum((ROUND(product_item_price, '. $rounding .')*product_quantity)+product_subtotal_discount) FROM #__virtuemart_order_items where `virtuemart_order_id`='.$ordid.'), '; if($calculate_billTaxAmount) { $sql .= '`order_billTaxAmount`= /*`order_shipment_tax`+`order_payment_tax`+*/ '.$calc_rules_tax_amount.' + '.$calc_rules_vattax_amount; } else { $sql .= '`order_billTaxAmount`="'.vRequest::getFloat('order_billTaxAmount').'"'; } $sql .= ' ,`coupon_discount`="'.vRequest::getFloat('coupon_discount').'"'; //$sql .= ',`order_total`=(SELECT sum(product_final_price*product_quantity) FROM #__virtuemart_order_items where `virtuemart_order_id`='.$ordid.')+`order_shipment`+`order_shipment_tax`+`order_payment`+`order_payment_tax`+'.$calc_rules_amount.','; $sql .= ', `order_total`= ROUND(((SELECT sum(product_final_price*product_quantity) FROM #__virtuemart_order_items where `virtuemart_order_id`='.$ordid.') + `order_shipment` +`order_payment` + `order_shipment_tax`+`order_payment_tax` - '.$calc_rules_discount_amount.' + coupon_discount),'. $rounding .')'; $sql .= ', `modified_on` = "'.$today.'"'; $sql .= ' WHERE `virtuemart_order_id`='.$ordid; $db->setQuery($sql); if ($db->execute() === false) { vmError('updateSingleItem '.$db->getError().' and '.$sql); } //} } } /** * Strange name is just temporarly * * @param unknown_type $order_id * @param unknown_type $order_status * @author Max Milbers */ var $useDefaultEmailOrderStatus = true; public function updateOrderStatus($orders=0, $order_id =0,$order_status=0){ //General change of orderstatus $total = 1 ; if(empty($orders)){ $orders = array(); $orderslist = vRequest::getVar('orders', array()); $total = 0 ; // Get the list of orders in post to update foreach ($orderslist as $key => $order) { if ( $orderslist[$key]['order_status'] !== $orderslist[$key]['current_order_status'] ) { $orders[$key] = $orderslist[$key]; $total++; } } } if(!is_array($orders)){ $orders = array($orders); } /* Process the orders to update */ $updated = 0; $error = 0; if ($orders) { // $notify = vRequest::getVar('customer_notified', array()); // ??? // $comments = vRequest::getVar('comments', array()); // ??? foreach ($orders as $virtuemart_order_id => $order) { if ($order_id >0) $virtuemart_order_id= $order_id; $this->useDefaultEmailOrderStatus = false; if($this->updateStatusForOneOrder($virtuemart_order_id,$order,true)){ $updated ++; } else { $error++; } } } $result = array( 'updated' => $updated , 'error' =>$error , 'total' => $total ) ; return $result ; } function safeUpdateOrderStatus ($orderOrId, $orderstatus, $allowed = array('P')) { if(is_int($orderOrId)){ $order = $this->getOrder($orderOrId); $virtuemart_order_id = $orderOrId; } else { $order = $orderOrId; $virtuemart_order_id = $order['details']['BT']->virtuemart_order_id; } if(!empty($order['details']['BT']) and $order['details']['BT']->order_status != $orderstatus and in_array($order['details']['BT']->order_status, $allowed)){ $oData['order_status'] = $orderstatus; $this->updateStatusForOneOrder($virtuemart_order_id, $oData); return true; } return false; } /** * Attention, if you use this function within your trigger take care of the last parameter, * you should define it, this parameter maybe set to false in future releases * * IMPORTANT: The $inputOrder can contain extra data by plugins * * @param $virtuemart_order_id * @param $inputOrder * @param bool $useTriggers * @return bool */ function updateStatusForOneOrder($virtuemart_order_id, $inputOrder, $useTriggers=true){ //vmdebug('updateStatusForOneOrder', $inputOrder); if(is_array($inputOrder)){ if( empty($virtuemart_order_id) and !empty($inputOrder['virtuemart_order_id'])){ $virtuemart_order_id = $inputOrder['virtuemart_order_id']; } else if(empty($inputOrder['virtuemart_order_id'])){ $inputOrder['virtuemart_order_id'] = $virtuemart_order_id; } } else if(is_object($inputOrder)){ if( empty($virtuemart_order_id) and !empty($inputOrder->virtuemart_order_id)){ $virtuemart_order_id = $inputOrder->virtuemart_order_id; } else if(empty($inputOrder->virtuemart_order_id)){ $inputOrder->virtuemart_order_id = $virtuemart_order_id; } //$virtuemart_order_id = $inputOrder->virtuemart_order_id; if(vmEcho::$_debug) VmError( 'updateStatusForOneOrder $inputOrder is object '.$virtuemart_order_id ); } if(empty($virtuemart_order_id)) { vmError('updateStatusForOneOrder empty virtuemart_order_id', 'updateStatusForOneOrder empty orderId'); vmTrace('updateStatusForOneOrder empty virtuemart_order_id'); return false; } /* Update the order */ $data = $this->getTable('orders'); $data->load($virtuemart_order_id); if(empty($data->created_on)){ vmError('updateStatusForOneOrder unknown virtuemart_order_id', 'updateStatusForOneOrder unknown orderId'); vmTrace('updateStatusForOneOrder unknown virtuemart_order_id'); return false; } $old_order_status = $data->order_status; $old_o_hash = $data->o_hash; $data->bind($inputOrder); $cp_rm = VmConfig::get('cp_rm',array('C')); if(!is_array($cp_rm)) $cp_rm = array($cp_rm); if ( in_array((string) $data->order_status,$cp_rm) ){ if (!empty($data->coupon_code)) { CouponHelper::RemoveCoupon($data->coupon_code); } } //First we must call the payment, the payment manipulates the result of the order_status if($useTriggers){ vDispatcher::importVMPlugins('vmpayment'); //Should we add this? $inputOrder $_returnValues = vDispatcher::trigger('plgVmOnUpdateOrderShipment',array(&$data,$old_order_status,$inputOrder)); foreach ($_returnValues as $_returnValue) { if ($_returnValue === true) { break; // Plugin was successfull } elseif ($_returnValue === false) { return false; // Plugin failed } // Ignore null status and look for the next returnValue } // Payment decides what to do when order status is updated $_returnValues = vDispatcher::trigger('plgVmOnUpdateOrderPayment',array(&$data,$old_order_status,$inputOrder)); foreach ($_returnValues as $_returnValue) { if ($_returnValue === true) { break; // Plugin was successfull } elseif ($_returnValue === false) { return false; // Plugin failed } // Ignore null status and look for the next returnValue } /** * If an order gets cancelled, fire a plugin event, perhaps * some authorization needs to be voided */ if ($data->order_status == "X") { //Should be renamed to plgVmOnCancelOrder vDispatcher::trigger('plgVmOnCancelPayment',array(&$data,$old_order_status)); } } if(empty($data->delivery_date)){ $del_date_type = VmConfig::get('del_date_type','m'); if(strpos($del_date_type,'os')!==FALSE){ //for example osS $os = substr($del_date_type,2); if($data->order_status == $os){ $date = JFactory::getDate(); $data->delivery_date = $date->toSQL(); } } else { vmLanguage::loadJLang('com_virtuemart_orders', true); $data->delivery_date = vmText::_('COM_VIRTUEMART_DELDATE_INV'); } } //if ($data->store()) { $task = vRequest::getCmd('task',0); $view = vRequest::getCmd('view',0); //The item_id of the request is already given as inputOrder by the calling function (controller). inputOrder could be manipulated by the //controller and so we must not use the request data here. $upd_items = vRequest::getVar('item_id',false); if($upd_items) { //get tax calc_value of product VatTax $db = JFactory::getDBO(); $sql = 'SELECT * FROM `#__virtuemart_order_calc_rules` WHERE `virtuemart_order_id` = "'.$virtuemart_order_id.'" ORDER BY virtuemart_order_item_id'; $db->setQuery( $sql ); $orderCalcs = $db->loadObjectList(); //vmdebug('$orderCalcs',$orderCalcs); $allTaxes = array(); //$taxes = array(); //$taxes['VatTax'] = array(); $orderCalcRulesTable = $this->getTable('order_calc_rules'); $data->order_salesPrice = 0.0; foreach( $inputOrder as $item_id => $order_item_data ) { if(!empty($item_id) and !is_integer($item_id) and strpos($item_id,'0-')!==0) continue; //Attention, we need the check against empty, else it continues for "0" //vmdebug('$order_item_data',$order_item_data); $order_item_data['current_order_status'] = $order_item_data['order_status']; if(!isset( $order_item_data['comments'] )) $order_item_data['comments'] = ''; $order_item_data = (object)$order_item_data; $order_item_data->virtuemart_order_id = $virtuemart_order_id; $order_item_data->virtuemart_order_item_id = $item_id; //$this->updateSingleItem($order_item->virtuemart_order_item_id, $data->order_status, $order['comments'] , $virtuemart_order_id, $data->order_pass); if(empty( $item_id )) { $inputOrder['comments'] .= ' '.vmText::sprintf( 'COM_VIRTUEMART_ORDER_PRODUCT_ADDED', $order_item_data->order_item_name ); } $toRemove = array(); $taxes = array(); if(empty($order_item_data->product_tax_id)){ $order_item_data->product_tax_id = array(); } else if(!is_array($order_item_data->product_tax_id)) { $order_item_data->product_tax_id = array($order_item_data->product_tax_id); } foreach( $orderCalcs as $i=>$calc ) { if($calc->virtuemart_order_item_id == $item_id){ $k = array_search( $calc->virtuemart_calc_id,$order_item_data->product_tax_id); if($k!==FALSE){ $calc->product_quantity = $order_item_data->product_quantity; //We need it later in the updateBill $taxes[$calc->calc_kind][$calc->virtuemart_calc_id] = $calc; unset($order_item_data->product_tax_id[$k]); } else if ($calc->calc_kind=='VatTax' or $calc->calc_kind=='Tax'){ $toRemove[] = $calc->virtuemart_order_calc_rule_id; } else { $taxes[$calc->calc_kind][$calc->virtuemart_calc_id] = $calc; } } } if(!empty($order_item_data->product_tax_id)){ //$orderCalcRulesTable = $this->getTable('order_calc_rules'); foreach( $order_item_data->product_tax_id as $pTaxId ) { if(empty($pTaxId))continue; $sql = 'SELECT * FROM `#__virtuemart_calcs` WHERE `virtuemart_calc_id` = "'.$pTaxId.'" '; $db->setQuery( $sql ); $newCalc = $db->loadObject(); $newCalc->virtuemart_order_calc_rule_id = 0; $newCalc->virtuemart_order_id = $order_item_data->virtuemart_order_id; //$newCalc->virtuemart_vendor_id = $order_item_data->virtuemart_vendor_id; $newCalc->virtuemart_order_item_id = $item_id; $newCalc->calc_rule_name = $newCalc->calc_name; if(!empty($order_item_data->product_item_price)){ $newCalc->calc_amount = $order_item_data->product_item_price * $newCalc->calc_value * 0.01 ; } else { $newCalc->calc_amount = $order_item_data->product_final_price * (1 - 1/( $newCalc->calc_value * 0.01 + 1)); } $newCalc->calc_mathop = '+%'; $orderCalcRulesTable->bindChecknStore($newCalc); vmdebug('added new tax',$newCalc->calc_amount,$newCalc); $taxes[$newCalc->calc_kind][$orderCalcRulesTable->virtuemart_calc_id] = $orderCalcRulesTable->loadFieldValues(false); vmdebug('added new tax',$taxes); } } foreach($toRemove as $virtuemart_order_calc_rule_id){ $orderCalcRulesTable->delete($virtuemart_order_calc_rule_id); vmdebug('To remove ',$virtuemart_order_calc_rule_id); } $orderItemTable = $this->updateSingleItem( $item_id, $order_item_data, true,$taxes, $data->virtuemart_user_id); //vmdebug('AFter updateSingleItem, my product_subtotal_with_tax',$order_item_data,$orderItemTable); foreach($taxes as $kind ){ foreach($kind as $tax){ $allTaxes[] = $tax; } } $data->order_salesPrice += $orderItemTable->product_final_price * $orderItemTable->product_quantity; //vmdebug('update Order new order_salesPrice',$data->order_salesPrice,$order_item_data->product_final_price); $inputOrder[$item_id] = $order_item_data; } //$pre = &$allTaxes; $pseudoOrder= array('items'=>$inputOrder,'calc_rules'=>$allTaxes); $pseudoOrder['details']['BT'] = $data; //vmdebug('my summarized rules $inputOrder before summarize',$inputOrder ); $summarizedRules = shopFunctionsF::summarizeRulesForBill($pseudoOrder,false); //vmdebug('my summarized rules',$summarizedRules ); //Determine ship/payment tax $idWithMax = 0; $maxValue = 0.0; if(!empty( $summarizedRules['taxBill'])) { foreach( $summarizedRules['taxBill'] as $rule ) { if($rule->calc_kind == 'taxRulesBill' or $rule->calc_kind == 'VatTax') { if(empty( $idWithMax ) or $maxValue<=$rule->subTotal) { $idWithMax = $rule->virtuemart_calc_id; $maxValue = $rule->subTotal; } } } } $undhandled = array('shipment','payment'); foreach($undhandled as $calc_kind){ $keyN = 'order_'.$calc_kind; $keyNTax = $keyN.'_tax'; //vmdebug('ShipPay Rules handling',$orderCalcs); //Find existing rule $rule = false; foreach( $orderCalcs as $i=>$rul ) { if($rul->calc_kind==$calc_kind){ $rule = $rul; } } //Seems there was no rule set if(!$rule){ $ocrTable = $this->getTable('order_calc_rules'); $rule = $ocrTable->loadFieldValues(false); $r = $summarizedRules['taxBill'][$idWithMax]; $rule->virtuemart_calc_id = $r->virtuemart_calc_id; $rule->virtuemart_vendor_id = $r->virtuemart_vendor_id; $rule->calc_rule_name = $r->calc_rule_name; $rule->virtuemart_order_id = $r->virtuemart_order_id; $rule->calc_value = $r->calc_value; $rule->calc_mathop = $r->calc_mathop; $rule->calc_currency = $r->calc_currency; //$rule->virtuemart_calc_id = $r->virtuemart_calc_id; $rule->calc_kind = $calc_kind; vmdebug('ShipPay Rules handling rule missing',$orderCalcs,$rule,$r); //$ocrTable = $this->getTable('order_calc_rules'); //$ocrTable->bindChecknStore($rule); } //$allTaxes[] = $rule; $data->{$keyN} = vRequest::getString($keyN,0.0); //There is a VAT available /* if( (/*count($summarizedRules['taxBill'])==1 or * VmConfig::get('radicalShipPaymentVat',true)) and isset($summarizedRules['taxBill'][$idWithMax])){ $r = $summarizedRules['taxBill'][$idWithMax]; $rule->calc_amount = $data->$keyN * ($r->calc_value * 0.01 ) ; $data->$keyNTax = round(floatval($data->$keyNTax),5); $rule->calc_amount = round(floatval($rule->calc_amount), 5); if($data->$keyNTax != $rule->calc_amount or $rule->virtuemart_calc_id != $r->virtuemart_calc_id){ //$data->$keyNTax = $rule->calc_amount; $rule->calc_rule_name = $r->calc_rule_name; $rule->virtuemart_order_id = $r->virtuemart_order_id; $rule->calc_value = $r->calc_value; $rule->calc_mathop = $r->calc_mathop; $rule->virtuemart_calc_id = $r->virtuemart_calc_id; //vmdebug('Updating rule '.$keyNTax,$data->$keyNTax,$rule,$r); $ocrTable = $this->getTable('order_calc_rules'); $ocrTable->bindChecknStore($rule); } //$summarizedRules['taxBill'][$idWithMax]->subTotal += $rule->calc_amount; $data->$keyNTax = $rule->calc_amount; //vmdebug('Use radicalShipPaymentVat with $idWithMax '.$idWithMax,$summarizedRules['taxBill'][$idWithMax]->subTotal,$data->$keyNTax, $rule); } else { */ $data->{$keyNTax} = 0.0; $t1 = 0.0; if(VmConfig::get('radicalShipPaymentVat',true)){ $r = $summarizedRules['taxBill'][$idWithMax]; /*$rule->calc_amount = $data->$keyN * ($r->calc_value * 0.01 ) ; $data->$keyNTax = round(floatval($data->$keyNTax),5); $rule->calc_amount = round(floatval($rule->calc_amount), 5); $data->$keyNTax = $rule->calc_amount;*/ $t1 = 0.0; $data->{$keyNTax} = (float)$r->calc_value * 0.01 * (float)$data->{$keyN}; } else { foreach($summarizedRules['taxBill'] as $in=>$vatrule){ if(!empty($data->order_salesPrice)){ $t1 = (float)$vatrule->calc_value * 0.01 * (float)$vatrule->subTotal/(float)$data->order_salesPrice; } else { $t1 = 0.0; } //vmdebug('ShipPay Rules store '.$vatrule->calc_value * 0.01.' * '. $vatrule->subTotal.'/'.$data->order_salesPrice.' = '.$t1); $data->{$keyNTax} += $t1 * (float)$data->{$keyN}; //$summarizedRules['taxBill'][$in]->calc_amount += $data->$keyNTax ; } } if($data->{$keyNTax} != $rule->calc_amount){ $rule->calc_amount = $data->{$keyNTax}; $rule->calc_value = $t1 * 100.0; //vmdebug('ShipPay Rules set',$rule); $ocrTable = $this->getTable('order_calc_rules'); $ocrTable->bindChecknStore($rule); } // } //vmdebug('Add rule to $allTaxes',$rule); $allTaxes[] = $rule; //} }//*/ $pseudoOrder= array('items'=>$inputOrder,'calc_rules'=>$allTaxes); $pseudoOrder['details']['BT'] = $data; //vmdebug('my summarized rules $inputOrder before summarize',$inputOrder ); $summarizedRules = shopFunctionsF::summarizeRulesForBill($pseudoOrder,true); $ocrTable = $this->getTable('order_calc_rules'); foreach($summarizedRules['taxBill'] as $r){ if($r->calc_kind=='payment' or $r->calc_kind=='shipment'){ $ocrTable->bindChecknStore($r); } } $this->calculatePaidByOS($data,$inputOrder); //prevents sending of email $inputOrder['customer_notified'] = 0; // invoice_locked should depend ideally on the existence of the invoice, but it would just be an extra query later, we do a new invoice anyway. if(VirtueMartModelInvoice::needInvoiceByOrderstatus($data->order_status) or VirtueMartModelInvoice::needInvoiceByOrderstatus($data->order_status,'inv_osr', array('R'))){ $data->invoice_locked = 1; //vmdebug('SET LOCK'); } //quorvia dont lock my invoices if (!empty(VmConfig::get('unlockInvoices',false))) { $data->invoice_locked = 0; } $data->store(); $this->updateBill($virtuemart_order_id, /*$vatTaxes,*/ $summarizedRules['taxBill']); } else { $update_lines = 1; if ($task==='updatestatus' and $view==='orders') { $lines = vRequest::getVar('orders'); $update_lines = $lines[$virtuemart_order_id]['update_lines']; } if($update_lines==1){ $q = 'SELECT virtuemart_order_item_id FROM #__virtuemart_order_items WHERE virtuemart_order_id="'.$virtuemart_order_id.'"'; $db = JFactory::getDBO(); $db->setQuery($q); $order_items = $db->loadObjectList(); if ($order_items) { foreach ($order_items as $item_id=>$order_item) { $this->updateSingleItem($order_item->virtuemart_order_item_id, $data); } } $this->calculatePaidByOS($data,$inputOrder); } //vmdebug('Going to store the order', $old_o_hash, $data->o_hash, $data->loadFieldValues()); // quorvia dont lock my invoice, // Milbo I think we dont need that if (!empty(VmConfig::get('unlockInvoices',false))) { $data->invoice_locked = 0; } $data->store(); } //Must be below the handling of the order items, else we must add an except as for "customer_notified" if(empty($inputOrder['comments'])){ $inputOrder['comments'] = ''; } else { $inputOrder['comments'] = trim($inputOrder['comments']); } $invM = VmModel::getModel('invoice'); //TODO use here needNewInvoiceNumber $inputOrder['order_status'] = $data->order_status; //vmdebug('updateStatusForOneOrder, a new invoice needed? ',(int)$data->invoice_locked, $old_order_status, $data->order_status, $old_o_hash, $data->o_hash); if(!$data->invoice_locked and ($old_order_status!=$data->order_status or $old_o_hash != $data->o_hash) and VirtueMartModelInvoice::isInvoiceToBeAttachByOrderstats($inputOrder['order_status'])){ $layout = 'invoice'; $checkHash = true; //$refundOrderStatus = VmConfig::get('inv_osr',array('R')); //if(!in_array($old_order_status, $refundOrderStatus) and VirtueMartModelInvoice::needInvoiceByOrderstatus($inputOrder['order_status'],'inv_osr', array('R') )){ if($old_order_status!=$data->order_status){ $checkHash = false; } if(VirtueMartModelInvoice::needInvoiceByOrderstatus($inputOrder['order_status'],'inv_osr', array('R'))){ $layout = 'refund'; } $inputOrder['o_hash'] = $data->o_hash; vmdebug('We need a new invoice ',$layout); $inputOrder['invoice_number'] = $invM->createReferencedInvoiceNumber($data->virtuemart_order_id, $inputOrder, $layout, $checkHash); } //We need a new invoice, therefore rename the old one. /*$inv_os = VmConfig::get('inv_os',array('C')); if(!is_array($inv_os)) $inv_os = array($inv_os); if($old_order_status!=$data->order_status and in_array($data->order_status,$inv_os)){ //$this->renameInvoice($data->virtuemart_order_id); vmdebug('my input order here',$inputOrder); $inputOrder['invoice_number'] = $this->createReferencedInvoice($data->virtuemart_order_id); }*/ /* Update the order history */ //update order histories needs the virtuemart_order_id $inputOrder['virtuemart_order_id'] = $virtuemart_order_id; //vmdebug('Notify customer calling todo this data is almost the same, we should merge and so we do not need to load again the just stored order ', $data, $inputOrder); $customer_notified = $this->notifyCustomer( $data->virtuemart_order_id , $inputOrder ); $inputOrder['customer_notified'] = (int)$customer_notified; $this->updateOrderHistory($inputOrder); //vDispatcher::importVMPlugins('vmcoupon'); $returnValues = vDispatcher::trigger('plgVmCouponUpdateOrderStatus', array($data, $old_order_status)); if(!empty($returnValues)){ foreach ($returnValues as $returnValue) { if ($returnValue !== null ) { return $returnValue; } } } return true; /*} else { return false; }*/ } /** * With point to reflect the problem that the value must not be set if $data->paidSet is set * @param $data * @param $inputOrder * @return mixed */ public function calculatePaidByOS(&$data, $inputOrder){ if(empty($data->paidSet)){ if(vmAccess::manager('order.status')){ $paid = vRequest::getFloat('paid',0); if($paid){ $data->paid = $paid; } } $os_trigger_paid = VmConfig::get('os_trigger_paid', array('C')); if(in_array($data->order_status,$os_trigger_paid)){ if(empty($data->paid)){ $data->paid = $data->order_total; $date = JFactory::getDate(); $today = $date->toSQL(); $data->paid_on = $today; } $itms = isset($inputOrder['items'])?$inputOrder['items']:$inputOrder; foreach ($itms as $id => $item) { if(!$item){ vmdebug('calculatePaidByOS $item is false ',$inputOrder); continue; } $os_trigger_refunds = VmConfig::get('os_trigger_refunds', array('R')); $order_status = (is_array($item) and isset($item['order_status']))? $item['order_status']: $item; //vmdebug('my order status $item',$item,$order_status); if(in_array($order_status,$os_trigger_refunds)){ //$ok = false; //VmInfo('Cannot set order to paid/unpaid, because there are refunded items. Please check the order manually '.$id); $data->paid -= $item->product_final_price * $item->product_quantity; } } //vmdebug('my calculatePaidByOS $data->paid',$data->paid); } } } /** * Get the information from the cart and create an order from it * * @author Oscar van Eijk * @param object $_cart The cart data * @return mixed The new ordernumber, false on errors */ public function createOrderFromCart($cart) { if ($cart === null) { vmError('createOrderFromCart() called without a cart - that\'s a programming bug','Can\'t create order, sorry.'); return false; } $usr = JFactory::getUser(); //$prices = $cart->getCartPrices(); if (($orderID = $this->_createOrder($cart, $usr)) == 0) { vmError('Couldn\'t create order','Couldn\'t create order'); return false; } if (!$this->_createOrderLines($orderID, $cart)) { vmError('Couldn\'t create order items','Couldn\'t create order items'); return false; } if (!$this-> _createOrderCalcRules($orderID, $cart) ) { vmError('Couldn\'t create order items','Couldn\'t create order items'); return false; } $this->_updateOrderHist($orderID); if (!$this->_writeUserInfo($orderID, $usr, $cart)) { vmError('Couldn\'t create order userinfo','Couldn\'t create order userinfo'); return false; } return $orderID; } /** * Write the order header record * * @author Oscar van Eijk * @param object $_cart The cart data * @param object $_usr User object * @param array $_prices Price data * @return integer The new ordernumber */ private function _createOrder($_cart, $_usr) { // TODO We need tablefields for the new values: // Shipment: // $_prices['shipmentValue'] w/out tax // $_prices['shipmentTax'] Tax // $_prices['salesPriceShipment'] Total // // Payment: // $_prices['paymentValue'] w/out tax // $_prices['paymentTax'] Tax // $_prices['paymentDiscount'] Discount // $_prices['salesPricePayment'] Total $_orderData = new stdClass(); $_orderData->virtuemart_order_id = null; $oldOrderNumber = ''; $this->deleteOldPendingOrder($_cart); $_orderData->virtuemart_user_id = $_usr->get('id'); $_orderData->virtuemart_vendor_id = $_cart->vendorId; $_orderData->customer_number = $_cart->customer_number; $_prices = $_cart->cartPrices; //Note as long we do not have an extra table only storing addresses, the virtuemart_userinfo_id is not needed. //The virtuemart_userinfo_id is just the id of a stored address and is only necessary in the user maintance view or for choosing addresses. //the saved order should be an snapshot with plain data written in it. // $_orderData->virtuemart_userinfo_id = 'TODO'; // $_cart['BT']['virtuemart_userinfo_id']; // TODO; Add it in the cart... but where is this used? Obsolete? $_orderData->order_total = $_prices['billTotal']; $_orderData->order_salesPrice = $_prices['salesPrice']; $_orderData->order_billTaxAmount = $_prices['billTaxAmount']; $_orderData->order_billDiscountAmount = $_prices['billDiscountAmount']; $_orderData->order_discountAmount = $_prices['discountAmount']; $_orderData->order_subtotal = $_prices['priceWithoutTax']; $_orderData->order_tax = $_prices['taxAmount']; $_orderData->order_shipment = $_prices['shipmentValue']; $_orderData->order_shipment_tax = $_prices['shipmentTax']; $_orderData->order_payment = $_prices['paymentValue']; $_orderData->order_payment_tax = $_prices['paymentTax']; if (!empty($_cart->cartData['VatTax'])) { $taxes = array(); foreach($_cart->cartData['VatTax'] as $k=>$VatTax) { $taxes[$k]['virtuemart_calc_id'] = $k; $taxes[$k]['calc_name'] = $VatTax['calc_name']; $taxes[$k]['calc_value'] = $VatTax['calc_value']; $taxes[$k]['result'] = $VatTax['result']; } $_orderData->order_billTax = vmJsApi::safe_json_encode($taxes); } if (!empty($_cart->cartData['couponCode'])) { $_orderData->coupon_code = $_cart->cartData['couponCode']; $_orderData->coupon_discount = $_prices['salesPriceCoupon']; } $_orderData->order_discount = $_prices['discountAmount']; // discount order_items $_orderData->order_status = 'P'; $_orderData->order_currency = $this->getVendorCurrencyId($_orderData->virtuemart_vendor_id); if (isset($_cart->pricesCurrency)) { $_orderData->user_currency_id = $_cart->pricesCurrency ; $currency = CurrencyDisplay::getInstance($_orderData->user_currency_id); if($_orderData->user_currency_id != $_orderData->order_currency){ $_orderData->user_currency_rate = $currency->convertCurrencyTo($_orderData->user_currency_id ,1.0,false); } else { $_orderData->user_currency_rate=1.0; } } $shoppergroups = $_cart->user->get('shopper_groups'); if (!empty($shoppergroups)) { $_orderData->user_shoppergroups = implode(',', $shoppergroups); } if (isset($_cart->paymentCurrency)) { $_orderData->payment_currency_id = $_cart->paymentCurrency ;//$this->getCurrencyIsoCode($_cart->pricesCurrency); if($_orderData->payment_currency_id != $_orderData->order_currency){ $currency = CurrencyDisplay::getInstance($_orderData->payment_currency_id); $_orderData->payment_currency_rate = $currency->convertCurrencyTo($_orderData->payment_currency_id ,1.0,false); } else { $_orderData->payment_currency_rate = 1.0; } } $_orderData->virtuemart_paymentmethod_id = $_cart->virtuemart_paymentmethod_id; $_orderData->virtuemart_shipmentmethod_id = $_cart->virtuemart_shipmentmethod_id; //Some payment plugins need a new order_number for any try $_orderData->order_number = ''; $_orderData->order_pass = ''; $_orderData->order_language = $_cart->order_language; $_orderData->ip_address = ShopFunctions::getClientIP();; $maskIP = VmConfig::get('maskIP','last'); if($maskIP=='last'){ $rpos = strrpos($_orderData->ip_address,'.'); $_orderData->ip_address = substr($_orderData->ip_address,0,($rpos+1)).'xx'; } //lets merge here the userdata from the cart to the order so that it can be used if(!empty($_cart->BT)){ $continue = array('created_on'=>1, 'created_by'=>1, 'modified_on'=>1, 'modified_by'=>1, 'locked_on'=>1, 'locked_by'=>1); foreach($_cart->BT as $k=>$v){ if(isset($continue[$k])) continue; $_orderData->{$k} = $v; } } $_orderData->STsameAsBT = $_cart->STsameAsBT; unset($_orderData->created_on); JPluginHelper::importPlugin('vmshopper'); $plg_datas = vDispatcher::trigger('plgVmOnUserOrder',array(&$_orderData)); if( empty($_cart->order_number)){ $i = 0; while($oldOrderNumber==$_orderData->order_number) { if($i>5) { $msg = 'Could not generate new unique ordernumber'; vmError($msg.', an ordernumber should contain at least one random char', $msg); break; } $_orderData->order_number = $this->genStdOrderNumber( $_orderData->virtuemart_vendor_id ); if(!empty($oldOrderNumber))vmdebug('Generated new ordernumber ',$oldOrderNumber,$_orderData->order_number); $i++; } } else { $_orderData->order_number = $_cart->order_number; } if(empty($_orderData->order_pass)){ $_orderData->order_pass = $this->genStdOrderPass(); } if(empty($_orderData->order_create_invoice_pass)){ $_orderData->order_create_invoice_pass = $this->genStdCreateInvoicePass(); } $orderTable = $this->getTable('orders'); $orderTable -> bindChecknStore($_orderData); if (!empty($_cart->cartData['couponCode'])) { //set the virtuemart_order_id in the Request for 3rd party coupon components (by Seyi and Max) vRequest::setVar ( 'virtuemart_order_id', $orderTable->virtuemart_order_id ); // If a gift coupon was used, remove it now CouponHelper::setInUseCoupon($_cart->cartData['couponCode'], true); } // the order number is saved into the session to make sure that the correct cart is emptied with the payment notification $_cart->order_number = $orderTable->order_number; $_cart->order_pass = $_orderData->order_pass; $_cart->virtuemart_order_id = $orderTable->virtuemart_order_id; $_cart->setCartIntoSession (); //VmEcho::$logDebug = 1; //vmdebug('_createOrder', $_cart->virtuemart_order_id, $orderTable->virtuemart_order_id); return $orderTable->virtuemart_order_id; } function deleteOldPendingOrder($cart){ $reUseTimeSql = VmConfig::get('reuseorders','30');vmdebug('deleteOldPendingOrder '.$reUseTimeSql); if(empty($reUseTimeSql)){ return false; } //else if($reUseTimeSql == 1){ $reUseTimeSql = '60'; //} $db = JFactory::getDbo(); $q = 'SELECT * FROM `#__virtuemart_orders` WHERE `order_status` = "P" '; if(!empty($cart->virtuemart_order_id)){ $q .= 'AND `virtuemart_order_id`= "'.$cart->virtuemart_order_id.'" '; } else if($cart->customer_number){ $q .= 'AND `customer_number`= "'.$cart->customer_number.'" '; } else { return false; } $jnow = JFactory::getDate(); $minusT = date('Y-m-d H:i:s', strtotime('-'.$reUseTimeSql.' minutes', strtotime($jnow))); $q .= 'AND `created_on` > "'.$minusT.'" '; $db->setQuery($q);vmdebug('deleteOldPendingOrder',$q); $order = $db->loadAssoc(); if($order) { $this->remove(array($order['virtuemart_order_id']),false); return $order['virtuemart_order_id']; } } private function getVendorCurrencyId($vendorId){ $q = 'SELECT `vendor_currency` FROM `#__virtuemart_vendors` WHERE `virtuemart_vendor_id`="'.(int)$vendorId.'" '; $db = JFactory::getDBO(); $db->setQuery($q); $vendorCurrency = $db->loadResult(); return $vendorCurrency; } /** * Write the BillTo record, and if set, the ShipTo record * * @author Oscar van Eijk * @param integer $_id Order ID * @param object $_usr User object * @param object $_cart Cart object * @return boolean True on success */ private function _writeUserInfo($_id, &$_usr, $_cart) { $_userInfoData = array(); $_userFieldsModel = VmModel::getModel('userfields'); $_userFieldsBT = $_userFieldsModel->getUserFields('account' , array('delimiters'=>true, 'captcha'=>true) , array('username', 'password', 'password2', 'user_is_vendor') ); $userFieldsCart = $_userFieldsModel->getUserFields( 'cart' , array('captcha' => true, 'delimiters' => true) // Ignore these types , array('user_is_vendor' ,'username','password', 'password2', 'agreed', 'address_type') // Skips ); $_userFieldsBT = array_merge($_userFieldsBT,$userFieldsCart); foreach ($_userFieldsBT as $_fld) { $_name = $_fld->name; if(!empty( $_cart->BT[$_name])){ if (is_array( $_cart->BT[$_name])) { $_userInfoData[$_name] = implode("|*|",$_cart->BT[$_name]); } else { $_userInfoData[$_name] = $_cart->BT[$_name]; } } } $_userInfoData['virtuemart_order_id'] = $_id; $_userInfoData['virtuemart_user_id'] = $_usr->get('id'); $_userInfoData['address_type'] = 'BT'; $db = JFactory::getDBO(); $q = ' SELECT `virtuemart_order_userinfo_id` FROM `#__virtuemart_order_userinfos` '; $q .= ' WHERE `virtuemart_order_id` = "'.$_id.'" AND `address_type` = "BT" '; $db->setQuery($q); if($vmOId = $db->loadResult()){ $_userInfoData['virtuemart_order_userinfo_id'] = $vmOId; } $order_userinfosTable = $this->getTable('order_userinfos'); if (!$order_userinfosTable->bindChecknStore($_userInfoData)){ return false; } if ($_cart->ST and empty($_cart->STsameAsBT)) { $_userInfoData = array(); $_userFieldsST = $_userFieldsModel->getUserFields('shipment' , array('delimiters'=>true, 'captcha'=>true) , array('username', 'password', 'password2', 'user_is_vendor') ); foreach ($_userFieldsST as $_fld) { $_name = $_fld->name; if(!empty( $_cart->ST[$_name])){ $_userInfoData[$_name] = $_cart->ST[$_name]; } } $_userInfoData['virtuemart_order_id'] = $_id; $_userInfoData['virtuemart_user_id'] = $_usr->get('id'); $_userInfoData['address_type'] = 'ST'; $q = ' SELECT `virtuemart_order_userinfo_id` FROM `#__virtuemart_order_userinfos` '; $q .= ' WHERE `virtuemart_order_id` = "'.$_id.'" AND `address_type` = "ST" '; $db->setQuery($q); if($vmOId = $db->loadResult()){ $_userInfoData['virtuemart_order_userinfo_id'] = $vmOId; } $order_userinfosTable = $this->getTable('order_userinfos'); if (!$order_userinfosTable->bindChecknStore($_userInfoData)){ return false; } } return true; } function handleStockAfterStatusChangedPerProduct($newState, $oldState, $tableOrderItems, $quantity) { vmdebug( 'handleStockAfterStatusChangedPerProduct '.$oldState.' '.$newState.' '. $quantity, $tableOrderItems->product_quantity); if($newState == $oldState and $quantity == $tableOrderItems->product_quantity) return; // $StatutWhiteList = array('P','C','X','R','S','N'); /*$db = JFactory::getDBO(); $db->setQuery('SELECT * FROM `#__virtuemart_orderstates` '); $StatutWhiteList = $db->loadAssocList('order_status_code');*/ $StatutWhiteList = VirtueMartModelOrderstatus::getOrderStatusNames(); // new product is statut N $StatutWhiteList['N'] = Array ( 'order_status_id' => 0 , 'order_status_code' => 'N' , 'order_stock_handle' => 'A'); if(!array_key_exists($oldState,$StatutWhiteList) or !array_key_exists($newState,$StatutWhiteList)) { vmError('The workflow for '.$newState.' or '.$oldState.' is unknown, take a look on model/orders function handleStockAfterStatusChanged','Can\'t process workflow, contact the shopowner. Status is '.$newState); return ; } // P Pending // C Confirmed // X Cancelled // R Refunded // S Shipped // N New or coming from cart // TO have no product setted as ordered when added to cart simply delete 'P' FROM array Reserved // don't set same values in the 2 arrays !!! // stockOut is in normal case shipped product //order_stock_handle // 'A' : stock Available // 'O' : stock Out // 'R' : stock reserved // the status decreasing real stock ? // $stockOut = array('S'); if ($StatutWhiteList[$newState]['order_stock_handle'] == 'O') $isOut = 1; else $isOut = 0; if ($StatutWhiteList[$oldState]['order_stock_handle'] == 'O') $wasOut = 1; else $wasOut = 0; // Stock change ? if ($isOut && !$wasOut) $product_in_stock = '-'; else if ($wasOut && !$isOut ) $product_in_stock = '+'; else $product_in_stock = '='; // the status increasing reserved stock(virtual Stock = product_in_stock - product_ordered) // $Reserved = array('P','C'); if ($StatutWhiteList[$newState]['order_stock_handle'] == 'R') $isReserved = 1; else $isReserved = 0; if ($StatutWhiteList[$oldState]['order_stock_handle'] == 'R') $wasReserved = 1; else $wasReserved = 0; if ($isReserved && !$wasReserved ) $product_ordered = '+'; else if (!$isReserved && $wasReserved ) $product_ordered = '-'; else $product_ordered = '='; $diff = $tableOrderItems->product_quantity - $quantity; if(!empty($diff) and $product_in_stock == '=' and $product_ordered == '='){ if($isReserved){ if($diff>0) $product_ordered = '+'; else $product_ordered = '-'; } if($isOut){ if($diff>0) $product_in_stock = '+'; else $product_ordered = '-'; } $quantity = abs($diff); } //Here trigger plgVmGetProductStockToUpdateByCustom $productModel = VmModel::getModel('product'); if (!empty($tableOrderItems->product_attribute)) { $virtuemart_product_id = $tableOrderItems->virtuemart_product_id; $product_attributes = vmJsApi::safe_json_decode( $tableOrderItems->product_attribute, true ); foreach( $product_attributes as $virtuemart_customfield_id => $param ) { if($param) { if(is_array( $param )) { reset( $param ); $customfield_id = key( $param ); } else { $customfield_id = $param; } if($customfield_id) { if($productCustom = VirtueMartModelCustomfields::getCustomEmbeddedProductCustomField( $customfield_id )) { if($productCustom->field_type == "E") { vDispatcher::importVMPlugins( 'vmcustom' ); vDispatcher::trigger( 'plgVmGetProductStockToUpdateByCustom', array(&$tableOrderItems, $param, $productCustom) ); } else if($productCustom->field_type == "PB"){ if(!is_array($tableOrderItems)) $tableOrderItems = array($tableOrderItems); $pr = $productModel->getProductSingle($productCustom->bundle_product_id); $tableOrderItems[] = $pr; } } } } } } // we can have more then one product in case of pack // in case of child, ID must be the child ID // TO DO use $prod->amount change for packs(eg. 1 computer and 2 HDD) if (is_array($tableOrderItems)) { foreach ($tableOrderItems as $prod ) { $productModel->updateStockInDB($prod, $quantity,$product_in_stock,$product_ordered); } } else { $productModel->updateStockInDB($tableOrderItems, $quantity,$product_in_stock,$product_ordered); } } /** * Create the ordered item records * * @author Oscar van Eijk * @author Kohl Patrick * @param integer $_id integer Order ID * @param object $_cart array The cart data * @return boolean True on success */ private function _createOrderLines($virtuemart_order_id, $cart) { $_orderItems = $this->getTable('order_items'); foreach ($cart->products as $priceKey=>$product) { if(!empty($product->customProductData)){ $_orderItems->product_attribute = vmJsApi::safe_json_encode($product->customProductData); } else { $_orderItems->product_attribute = ''; } $_orderItems->virtuemart_order_item_id = null; $_orderItems->virtuemart_order_id = $virtuemart_order_id; $_orderItems->virtuemart_vendor_id = $product->virtuemart_vendor_id; $_orderItems->virtuemart_product_id = $product->virtuemart_product_id; $_orderItems->order_item_sku = $product->product_sku; $_orderItems->order_item_name = $product->product_name; $_orderItems->product_quantity = $product->quantity; $_orderItems->product_item_price = $product->allPrices[$product->selectedPrice]['basePriceVariant']; $_orderItems->product_basePriceWithTax = $product->allPrices[$product->selectedPrice]['basePriceWithTax']; //$_orderItems->product_tax = $_cart->pricesUnformatted[$priceKey]['subtotal_tax_amount']; $_orderItems->product_tax = $product->allPrices[$product->selectedPrice]['taxAmount']; $_orderItems->product_final_price = $product->allPrices[$product->selectedPrice]['salesPrice']; $_orderItems->product_subtotal_discount = $product->allPrices[$product->selectedPrice]['subtotal_discount']; $_orderItems->product_subtotal_with_tax = $product->allPrices[$product->selectedPrice]['subtotal_with_tax']; $_orderItems->product_priceWithoutTax = $product->allPrices[$product->selectedPrice]['priceWithoutTax']; $_orderItems->product_discountedPriceWithoutTax = $product->allPrices[$product->selectedPrice]['discountedPriceWithoutTax']; $_orderItems->order_status = 'P'; if (!$_orderItems->check()) { return false; } //The check may set here a wrong vendorId, we replace it again with the right one. $_orderItems->virtuemart_vendor_id = $product->virtuemart_vendor_id; // Save the record to the database if (!$_orderItems->store()) { return false; } $product->virtuemart_order_item_id = $_orderItems->virtuemart_order_item_id; $this->handleStockAfterStatusChangedPerProduct( $_orderItems->order_status,'N',$_orderItems,$_orderItems->product_quantity); } return true; } /** * Create the ordered item records * * @author Valerie Isaksen * @param integer $_id integer Order ID * @param object $_cart array The cart data * @return boolean True on success */ private function _createOrderCalcRules($order_id, $_cart) { $productKeys = array_keys($_cart->products); $calculation_kinds = array('DBTax','Tax','VatTax','DATax','Marge'); foreach($productKeys as $key){ foreach($calculation_kinds as $calculation_kind) { if(!isset($_cart->cartPrices[$key][$calculation_kind])) continue; $productRules = $_cart->cartPrices[$key][$calculation_kind]; foreach($productRules as $rule){ if(empty($rule[4])){ continue; } $orderCalcRules = $this->getTable('order_calc_rules'); $orderCalcRules->virtuemart_order_calc_rule_id= null; $orderCalcRules->virtuemart_calc_id= $rule[7]; $orderCalcRules->virtuemart_order_item_id = $_cart->products[$key]->virtuemart_order_item_id; $orderCalcRules->calc_rule_name = $rule[0]; $orderCalcRules->calc_amount = 0; if(isset($_cart->cartData['VatTax'][$rule[7]]['result'])) $orderCalcRules->calc_result = $_cart->cartData['VatTax'][$rule[7]]['result']; if ($calculation_kind == 'VatTax') { $orderCalcRules->calc_amount = $_cart->cartPrices[$key]['taxAmount']; //$orderCalcRules->calc_result = $_cart->cartData['VatTax'][$rule[7]]['result']; } $orderCalcRules->calc_value = $rule[1]; $orderCalcRules->calc_mathop = $rule[2]; $orderCalcRules->calc_kind = $calculation_kind; $orderCalcRules->calc_currency = $rule[4]; $orderCalcRules->calc_params = $rule[5]; $orderCalcRules->virtuemart_vendor_id = $rule[6]; $orderCalcRules->virtuemart_order_id = $order_id; if (!$orderCalcRules->check()) { vmdebug('_createOrderCalcRules check product rule ',$this); return false; } // Save the record to the database if (!$orderCalcRules->store()) { vmdebug('_createOrderCalcRules store product rule ',$this); return false; } } } } $Bill_calculation_kinds=array('DBTaxRulesBill', 'taxRulesBill', 'DATaxRulesBill'); foreach($Bill_calculation_kinds as $calculation_kind) { foreach($_cart->cartData[$calculation_kind] as $rule){ $orderCalcRules = $this->getTable('order_calc_rules'); $orderCalcRules->virtuemart_order_calc_rule_id = null; $orderCalcRules->virtuemart_calc_id= $rule['virtuemart_calc_id']; $orderCalcRules->calc_rule_name= $rule['calc_name']; $orderCalcRules->calc_amount = $_cart->cartPrices[$rule['virtuemart_calc_id'].'Diff']; if ($calculation_kind == 'taxRulesBill' and !empty($_cart->cartData['VatTax'][$rule['virtuemart_calc_id']]['result'])) { $orderCalcRules->calc_result = $_cart->cartData['VatTax'][$rule['virtuemart_calc_id']]['result']; } $orderCalcRules->calc_kind=$calculation_kind; $orderCalcRules->calc_currency=$rule['calc_currency']; $orderCalcRules->calc_value=$rule['calc_value']; $orderCalcRules->calc_mathop=$rule['calc_value_mathop']; $orderCalcRules->virtuemart_order_id=$order_id; $orderCalcRules->calc_params=$rule['calc_params']; $orderCalcRules->virtuemart_vendor_id = $rule['virtuemart_vendor_id']; if (!$orderCalcRules->check()) { return false; } // Save the record to the database if (!$orderCalcRules->store()) { return false; } } } if(!empty($_cart->virtuemart_paymentmethod_id)){ if(empty($_cart->cartPrices['payment_calc_id'])){ } else { $orderCalcRules = $this->getTable('order_calc_rules'); $calcModel = VmModel::getModel('calc'); $calcModel->setId($_cart->cartPrices['payment_calc_id']); $calc = $calcModel->getCalc(); if(empty($calc->calc_currency) or empty($calc->calc_value)) { } else { $orderCalcRules->virtuemart_order_calc_rule_id = null; $orderCalcRules->virtuemart_calc_id = $calc->virtuemart_calc_id; $orderCalcRules->calc_kind = 'payment'; $orderCalcRules->calc_rule_name = $calc->calc_name; //No translation here! $orderCalcRules->calc_amount = $_cart->cartPrices['paymentTax']; $orderCalcRules->calc_value = $calc->calc_value; $orderCalcRules->calc_mathop = $calc->calc_value_mathop; $orderCalcRules->calc_currency = $calc->calc_currency; $orderCalcRules->calc_params = $calc->calc_params; $orderCalcRules->virtuemart_vendor_id = $calc->virtuemart_vendor_id; $orderCalcRules->virtuemart_order_id = $order_id; if (!$orderCalcRules->check()) { } else { // Save the record to the database if (!$orderCalcRules->store()) { return false; } } } } } if(!empty($_cart->virtuemart_shipmentmethod_id)){ if(empty($_cart->cartPrices['shipment_calc_id'])){ } else { $orderCalcRules = $this->getTable('order_calc_rules'); $calcModel = VmModel::getModel('calc'); $calcModel->setId($_cart->cartPrices['shipment_calc_id']); $calc = $calcModel->getCalc(); if(empty($calc->calc_currency) or empty($calc->calc_value)) { } else { $orderCalcRules->virtuemart_order_calc_rule_id = null; $orderCalcRules->virtuemart_calc_id = $calc->virtuemart_calc_id; $orderCalcRules->calc_kind = 'shipment'; $orderCalcRules->calc_rule_name = vmText::_($calc->calc_name); $orderCalcRules->calc_amount = $_cart->cartPrices['shipmentTax']; $orderCalcRules->calc_value = $calc->calc_value; $orderCalcRules->calc_mathop = $calc->calc_value_mathop; $orderCalcRules->calc_currency = $calc->calc_currency; $orderCalcRules->calc_params = $calc->calc_params; $orderCalcRules->virtuemart_vendor_id = $calc->virtuemart_vendor_id; $orderCalcRules->virtuemart_order_id = $order_id; if (!$orderCalcRules->check()) { return false; } else { // Save the record to the database if (!$orderCalcRules->store()) { return false; } } } } } return true; } /** * Update the order history * * @param $id Order ID * @param $status New order status (default: P) * @param $notified 1 (default) if the customer was notified, 0 otherwise * @param $comment (Customer) comment, default empty */ public function _updateOrderHist($id, $status = 'P', $notified = 0, $comment = '') { //$inputOrder = array('virtuemart_order_id'=>$id, 'order_status'=>$status, 'customer_notified'=>$notified, 'comments'=>$comment); $order = $this->getTable('orders'); $order->load($id); $values = $order->getProperties(); $values['order_status_code'] = $status; $values['customer_notified'] = $notified; $values['comments'] = $comment; return $this->updateOrderHistory($values); } public function updateOrderHistory($inputOrder){ if(!empty($inputOrder['virtuemart_order_id'])){ //Depending on the used process, it can happen that order_status_code is given as order status if (empty($inputOrder['order_status_code']) && (!empty($inputOrder['order_status']))){ $inputOrder['order_status_code'] = $inputOrder['order_status']; } /*$db = JFactory::getDbo(); $q = 'SELECT * FROM `#__virtuemart_order_histories` WHERE `virtuemart_order_id`="'.$inputOrder['virtuemart_order_id'].'" ORDER BY `created_on` DESC LIMIT 1'; $db->setQuery($q); $oldHistoryRow = $db->loadObject();*/ //if(empty($oldHistoryRow) or $oldHistoryRow->order_status_code!=$inputOrder['order_status_code']){ $_orderHist = $this->getTable('order_histories'); $_orderHist->bindChecknStore($inputOrder); //} } } /** * Update the order item history * * @author Oscar van Eijk,kohl patrick * @param $_id Order ID * @param $_status New order status (default: P) * @param $_notified 1 (default) if the customer was notified, 0 otherwise * @param $_comment (Customer) comment, default empty */ private function _updateOrderItemHist($_id, $status = 'P', $notified = 1, $comment = '') { $_orderHist = $this->getTable('order_item_histories'); $_orderHist->virtuemart_order_item_id = $_id; $_orderHist->order_status_code = $status; $_orderHist->customer_notified = $notified; $_orderHist->comments = $comment; $_orderHist->store(); } /** * Creates a standard order password */ static public function genStdOrderPass(){ $chrs = "ABCDEFGHJKLMNPQRSTUVWXYZ"; $chrs.= "abcdefghijkmnopqrstuvwxyz"; $chrs.= "123456789"; return 'p_'.vmCrypt::getToken(VmConfig::get('randOrderPw',8),$chrs); } static public function genStdCreateInvoicePass(){ return vmCrypt::getToken(8); } /** * Generate a unique ordernumber using getHumanToken, which is a random token * with only upper case chars and without 0 and O to prevent missreadings * @author Max Milbers * @param integer $virtuemart_vendor_id For the correct count * @return string A unique ordernumber */ static public function genStdOrderNumber($virtuemart_vendor_id=1, $length = 4){ $db = JFactory::getDBO(); $q = 'SELECT COUNT(1) FROM #__virtuemart_orders WHERE `virtuemart_vendor_id`="'.$virtuemart_vendor_id.'"'; $db->setQuery($q); //We can use that here, because the order_number is free to set, the invoice_number must often follow special rules $c = $db->loadResult(); $c = $c + (int)VM_ORDER_OFFSET; $str = vmCrypt::getHumanToken(VmConfig::get('randOrderNr',$length)).'0'.$c; return $str; } /** * Generate a unique ordernumber. This is done in a similar way as VM1.1.x, although * the reason for this is unclear to me :-S * @deprecated * @param integer $uid The user ID. Defaults to 0 for guests * @return string A unique ordernumber */ static public function generateOrderNumber($uid = 0,$length=5, $virtuemart_vendor_id=1) { return self::genStdOrderNumber($virtuemart_vendor_id, $length); } /** * Notifies the customer that the Order Status has been changed * * @author Christopher Roussel, Valérie Isaksen, Max Milbers * */ public function notifyCustomer($virtuemart_order_id, $newOrderData = 0 ) { //Important, the data of the order update mails, payments and invoice should //always be in the database, so using getOrder is the right method $vendorModel = VmModel::getModel('vendor'); //Lets set the language to the Shop default $prevLang = VmConfig::$vmlangTag; shopFunctionsF::loadOrderLanguages(VmConfig::$jDefLangTag); $order = $this->getOrder($virtuemart_order_id); $vars = array(); $vars['orderDetails']=$order; $vars['statusemailoverride'] = ''; // quorvia - get a unique layout for this order status if configured $orderstatesModel = VmModel::getModel ('Orderstatus'); $orderstatuses = $orderstatesModel->getOrderStatusList (false); $statuscodes = array_column($orderstatuses, 'order_status_code'); $srow = array_search((string)$order['details']['BT']->order_status,$statuscodes); if(isset($srow)){ // vars gets reset every notify so ok here if(!empty($orderstatuses[$srow]->order_status_email_layout)){ $vars['statusemailoverride'] = $orderstatuses[$srow]->order_status_email_layout; } } //quorvia end $payment_name = $shipment_name=''; vDispatcher::importVMPlugins('vmpayment'); $returnValues = vDispatcher::trigger('plgVmOnShowOrderFEShipment',array( $order['details']['BT']->virtuemart_order_id, $order['details']['BT']->virtuemart_shipmentmethod_id, &$shipment_name)); $returnValues = vDispatcher::trigger('plgVmOnShowOrderFEPayment',array( $order['details']['BT']->virtuemart_order_id, $order['details']['BT']->virtuemart_paymentmethod_id, &$payment_name)); $order['shipmentName'] = $shipment_name; $order['paymentName'] = $payment_name; if($newOrderData!=0){ //We do not really need that $vars['newOrderData'] = (array)$newOrderData; } //$vars['includeComments'] = vRequest::getVar('customer_notified', array()); //I think this is misleading, I think it should always ask for example $vars['newOrderData']['doVendor'] directly //Using this function garantue us that it is always there. If the vendor should be informed should be done by the plugins //We may add later something to the method, defining this better $vars['url'] = 'url'; if(!isset($newOrderData['doVendor'])) $vars['doVendor'] = false; else $vars['doVendor'] = $newOrderData['doVendor']; $invoice = $this->getInvoiceIfAvailable($order); if($invoice){ $vars['mediaToSend'][] = $invoice; } $virtuemart_vendor_id = $order['details']['BT']->virtuemart_vendor_id; $vendorEmail = array(); $vendorEmail[] = $vars['vendorEmail'] = $vendorModel->getVendorEmail($virtuemart_vendor_id); $addVendorEmails = VmConfig::get('addVendorEmail',''); if (!empty($addVendorEmails)) $vendorEmail = array_merge($vendorEmail,explode(';',$addVendorEmails)); $vendor = $vendorModel->getVendor($virtuemart_vendor_id); $vars['vendor'] = $vendor; //Mail for vendor $orderstatusForVendorEmail = VmConfig::get('email_os_v',array('U','C','R','X')); if(!is_array($orderstatusForVendorEmail)) $orderstatusForVendorEmail = array($orderstatusForVendorEmail); if ( in_array((string)$order['details']['BT']->order_status,$orderstatusForVendorEmail)){ //shopFunctionsF::loadOrderLanguages(VmConfig::$jDefLangTag); //VmConfig::setLanguageByTag(VmConfig::$jDefLangTag); $view = shopFunctionsF::prepareViewForMail('invoice', $vars); $res = shopFunctionsF::sendVmMail( $view, $vendorEmail, TRUE ); } if (isset($newOrderData['customer_notified']) && $newOrderData['customer_notified']==0) { vmdebug('notifyCustomer return cause customer_notified == 0'); return false; } // Send the email //$res = shopFunctionsF::renderMail('invoice', $order['details']['BT']->email, $vars, null,$vars['doVendor'],$this->useDefaultEmailOrderStatus); $sendMail = false; if(!$this->useDefaultEmailOrderStatus and isset($vars['newOrderData']['customer_notified']) and $vars['newOrderData']['customer_notified']==1){ $sendMail = true; vmdebug('Send mail by form command'); } else { $orderstatusForShopperEmail = VmConfig::get('email_os_s',array('U','C','S','R','X')); if(!is_array($orderstatusForShopperEmail)) $orderstatusForShopperEmail = array($orderstatusForShopperEmail); if ( in_array((string) $vars['orderDetails']['details']['BT']->order_status,$orderstatusForShopperEmail) ){ $sendMail = true; vmdebug('renderMail by default orderstati'); } } shopFunctionsF::loadOrderLanguages(VmConfig::$vmlangTag); $res = true; if($sendMail){ if(!empty($vars['orderDetails']['details']) and !empty($vars['orderDetails']['details']['BT']->order_language)) { $orderLang = $vars['orderDetails']['details']['BT']->order_language; if(VmConfig::$vmlangTag!=$orderLang){ shopFunctionsF::loadOrderLanguages($orderLang); $vendor = $vendorModel->getVendor($virtuemart_vendor_id); $vars['vendor'] = $vendor; $vars['orderDetails'] = $this->getOrder($virtuemart_order_id); } } $shopperEmail = array(); $shopperEmailFields = VmConfig::get('email_sf_s',array('email')); foreach ($shopperEmailFields as $field) { if (!empty($order['details']['BT']->{$field})) $shopperEmail[] = $order['details']['BT']->{$field}; } if (count($shopperEmail) < 1) $shopperEmail[] = $order['details']['BT']->email; $view = shopFunctionsF::prepareViewForMail('invoice', $vars); $res = shopFunctionsF::sendVmMail( $view, $shopperEmail, false ); //invoice_sent /*$orderTable = $this->getTable('orders'); $orderTable->virtuemart_order_id = $virtuemart_order_id; $orderTable->toggle( 'invoice_sent', 1);*/ } if(is_object($res) or !$res){ $string = 'COM_VIRTUEMART_NOTIFY_CUSTOMER_ERR_SEND'; vmdebug('notifyCustomer function shopFunctionsF::renderMail throws JException'); $res = 0; } //We need this, to prevent that a false alert is thrown. else if ($res and $res!=-1) { $string = 'COM_VIRTUEMART_NOTIFY_CUSTOMER_SEND_MSG'; } if($res!=-1){ vmLanguage::setLanguageByTag(vmLanguage::$jSelLangTag); vmInfo( vmText::_($string,false).' '.$order['details']['BT']->first_name.' '.$order['details']['BT']->last_name. ', '.$order['details']['BT']->email); } //quicknDirty to prevent that an email is sent twice if(VmConfig::isSite()){ $cart = VirtueMartCart::getCart(); $cart->customer_notified = true; } VmLanguage::setLanguageByTag($prevLang); return $sendMail; } /** getInvoiceIfAvailable called in notify customer. * * calls VirtueMartControllerInvoice->getInvoicePDF, which calls VmPdf::createVmPdf * @param $order * @return false|int|mixed|string|void */ public function getInvoiceIfAvailable($order){ //vmdebug('getInvoiceIfAvailable start',$order ); $inv = false; $invoiceNumberDate = array(); $force_create_invoice=vRequest::getInt('create_invoice', -1); $invM = VmModel::getModel('invoice'); //TODO we need an array of orderstatus if ( /*/empty($order['details']['BT']->invoice_locked) and */($force_create_invoice==1 or $invM->isInvoiceToBeAttachByOrderstats($order['details']['BT']->order_status)) ){ $res = $invM->getExistingIfUnlockedCreateNewInvoiceNumber($order['details']['BT'], $invoiceNumberDate); if ($res and !shopFunctionsF::InvoiceNumberReserved($res[0])) { $controller = new VirtueMartControllerInvoice( array( 'model_path' => VMPATH_ADMIN .'/models', 'view_path' => VMPATH_SITE .'/views' )); $lTag = VmConfig::$vmlangTag; $inv = $controller->getInvoicePDF($order); vmLanguage::setLanguageByTag($lTag); } } vmdebug('getInvoiceIfAvailable',$inv); return $inv; } /** * Retrieve the details for an order line item. * * @author RickG * @param string $orderId Order id number * @param string $orderLineId Order line item number * @return object Object containing the order item details. */ function getOrderLineDetails($orderId, $orderLineId) { $table = $this->getTable('order_items'); if ($table->load((int)$orderLineId)) { return $table; } else { $table->reset(); $table->virtuemart_order_id = $orderId; return $table; } } /** * Save an order line item. * * @author RickG * @return boolean True of remove was successful, false otherwise */ function saveOrderLineItem($data) { if(!vmAccess::manager('orders.edit')) { return false; } $table = $this->getTable('order_items'); //Done in the table already vDispatcher::importVMPlugins('vmpayment'); $_returnValues = vDispatcher::trigger('plgVmOnUpdateOrderLineShipment',array( $data)); foreach ($_returnValues as $_retVal) { if ($_retVal === false) { // Stop as soon as the first active plugin returned a failure status return; } } $_returnValues = vDispatcher::trigger('plgVmOnUpdateOrderLinePayment',array( $data)); foreach ($_returnValues as $_retVal) { if ($_retVal === false) { // Stop as soon as the first active plugin returned a failure status return; } } $table->bindChecknStore($data); return true; } /** * */ function removePSDataOfOrder($orderId, $auth = true){ if($auth and !vmAccess::manager('orders.delete')) { return false; } $psTypes = array('shipment','payment'); $db = JFactory::getDbo(); foreach($psTypes as $_psType){ $idM = 'virtuemart_'.$_psType.'method_id'; if(!empty($order['details']['BT']->{$idM})){ $q = 'SELECT `'.$_psType.'_element` FROM `#__virtuemart_'.$_psType.'methods` '; $q .= 'WHERE `virtuemart_'.$_psType.'method_id` = "'.(int)$order['details']['BT']->{$idM}.'" '; $db->setQuery($q); $plg_name = $db->loadResult(); if(empty($plg_name)) continue; $_tablename = '#__virtuemart_' . $_psType . '_plg_' . $plg_name; $q = 'DELETE FROM '.$_tablename.' WHERE virtuemart_order_id="'.$orderId.'"'; $db->setQuery($q); $db->execute(); } } } /** * @author Max Milbers * * remove product from order item table * @param $virtuemart_order_id Order to clear * @param $auth * @return boolean True of remove was successful, false otherwise * */ function removeOrderItems ($virtuemart_order_id, $auth = true){ if($auth and !vmAccess::manager('orders.edit')) { return false; } $q ='DELETE from `#__virtuemart_order_items` WHERE `virtuemart_order_id` = ' .(int) $virtuemart_order_id; $db = JFactory::getDBO(); $db->setQuery($q); $ok = true; if ($db->execute() === false) { vmError($db->getError()); $ok = true; } $q ='DELETE from `#__virtuemart_order_calc_rules` WHERE `virtuemart_order_id` = ' .(int) $virtuemart_order_id; $db = JFactory::getDBO(); $db->setQuery($q); if ($db->execute() === false) { vmError($db->getError()); $ok = true; } $q = "DELETE FROM `#__virtuemart_order_histories` WHERE `virtuemart_order_id`=".(int) $virtuemart_order_id; $this->_db->setQuery($q); $this->_db->execute(); return $ok; } /** * Remove an order line item. * * @author RickG * @param string $orderLineId Order line item number * @return boolean True of remove was successful, false otherwise */ function removeOrderLineItem($orderLineId, $auth = true) { if($auth and !vmAccess::manager('orders.edit')) { return false; } $item = $this->getTable('order_items'); if (!$item->load($orderLineId)) { return false; } //Why should the stock change, when the order is deleted? //answer : when creating an order (P) the stock is reserved $this->handleStockAfterStatusChangedPerProduct('X', $item->order_status, $item,$item->product_quantity); //take data for history $data = $item->getProperties(); if (!VmConfig::get('ordersAddOnly',false) and $item->delete($orderLineId)) { $data['action'] = 'deleted'; $tableHist = $this->getTable('order_item_histories'); $tableHist->bindChecknStore($data); $q = "DELETE FROM `#__virtuemart_order_calc_rules` WHERE `virtuemart_order_item_id`=".$orderLineId; $this->_db->setQuery($q); $this->_db->execute();//*/ return true; } else { return false; } } /** * Delete all record ids selected * * @author Max Milbers * @author Patrick Kohl * @return boolean True is the delete was successful, false otherwise. */ public function remove($ids, $auth = true) { if($auth and !vmAccess::manager('orders.delete')) { return false; } $invM = VmModel::getModel('invoice'); $table = $this->getTable($this->_maintablename); $removedOrderMsgs=array(); foreach($ids as $id) { $order = $this->getOrder($id); $invoice = $invM->hasInvoice($id); if ($invoice) { if($auth){ $removedOrderMsgs [$order['details']['BT']->order_number]= 'COM_VIRTUEMART_ORDER_NOT_ALLOWED_TO_DELETE'; continue; } else { $invoice->delete(); } } if(!empty($order['items'])){ foreach($order['items'] as $it){ $this->removeOrderLineItem($it->virtuemart_order_item_id, $auth); } } $this->removeOrderItems($id, $auth); $this->removePSDataOfOrder($id, $auth); // rename invoice number by adding the date, and update the invoice table //$this->renameInvoice($id ); //there must be no invoice, (checked above) if (!$table->delete((int)$id)) { $removedOrderMsgs [$order['details']['BT']->order_number] = 'COM_VIRTUEMART_ORDER_PB_WHILE_DELETING'; } $removedOrderMsgs [$order['details']['BT']->order_number] =true; } return $removedOrderMsgs; } /** Update order head record * * @author Ondřej Spilka * @author Maik Künnemann * @return boolean True is the update was successful, otherwise false. */ public function UpdateOrderHead($virtuemart_order_id, $_orderData) { if(!vmAccess::manager('orders.edit')){ return false; } $orderTable = $this->getTable('orders'); $orderTable->load($virtuemart_order_id); if (!$orderTable->bindChecknStore($_orderData, true)){ return false; } $_userInfoData = array(); $_userFieldsModel = VmModel::getModel('userfields'); //bill to $_userFieldsCart = $_userFieldsModel->getUserFields('account' , array('delimiters'=>true, 'captcha'=>true) , array('username', 'password', 'password2', 'user_is_vendor') ); $_userFieldsBT = $_userFieldsModel->getUserFields('cart' , array('delimiters'=>true, 'captcha'=>true) , array('username', 'password', 'password2', 'user_is_vendor') ); $_userFieldsBT = array_merge((array)$_userFieldsBT,(array)$_userFieldsCart); foreach ($_userFieldsBT as $_fld) { $_name = $_fld->name; if(isset( $_orderData["BT_{$_name}"])){ $_userInfoData[$_name] = $_orderData["BT_{$_name}"]; } } $_userInfoData['virtuemart_order_id'] = $virtuemart_order_id; $_userInfoData['address_type'] = 'BT'; $order_userinfosTable = $this->getTable('order_userinfos'); $order_userinfosTable->load($virtuemart_order_id, 'virtuemart_order_id'," AND address_type='BT'"); if (!$order_userinfosTable->bindChecknStore($_userInfoData, true)){ return false; } //ship to $_userFieldsST = $_userFieldsModel->getUserFields('account' , array('delimiters'=>true, 'captcha'=>true) , array('username', 'password', 'password2', 'user_is_vendor') ); $_userInfoData = array(); foreach ($_userFieldsST as $_fld) { $_name = $_fld->name; if(isset( $_orderData["ST_{$_name}"])){ $_userInfoData[$_name] = $_orderData["ST_{$_name}"]; } } $_userInfoData['virtuemart_order_id'] = $virtuemart_order_id; if (empty($_orderData['STsameAsBT'])) { $_userInfoData['address_type'] = 'ST'; $order_userinfosTable = $this->getTable('order_userinfos'); $order_userinfosTable->load($virtuemart_order_id, 'virtuemart_order_id'," AND address_type='ST'"); // if this is new ST record we need the user_id from the order if(empty($order_userinfosTable->virtuemart_user_id)){ $_userInfoData['virtuemart_user_id'] = $orderTable->virtuemart_user_id; } if (!$order_userinfosTable->bindChecknStore($_userInfoData, true)){ return false; } } $orderModel = VmModel::getModel('orders'); $order = $orderModel->getOrder($virtuemart_order_id); // Update Payment Method if($_orderData['old_virtuemart_paymentmethod_id'] != $_orderData['virtuemart_paymentmethod_id']) { $db = JFactory::getDBO(); $db->setQuery( 'SELECT `payment_element` FROM `#__virtuemart_paymentmethods` , `#__virtuemart_orders` WHERE `#__virtuemart_paymentmethods`.`virtuemart_paymentmethod_id` = `#__virtuemart_orders`.`virtuemart_paymentmethod_id` AND `virtuemart_order_id` = ' . $virtuemart_order_id ); $paymentTable = '#__virtuemart_payment_plg_'. $db->loadResult(); $db->setQuery("DELETE from `". $paymentTable ."` WHERE `virtuemart_order_id` = " . $virtuemart_order_id); if ($db->execute() === false) { vmError($db->getError()); return false; } else { JPluginHelper::importPlugin('vmpayment'); } } // Update Shipment Method if($_orderData['old_virtuemart_shipmentmethod_id'] != $_orderData['virtuemart_shipmentmethod_id']) { $db->setQuery( 'SELECT `shipment_element` FROM `#__virtuemart_shipmentmethods` , `#__virtuemart_orders` WHERE `#__virtuemart_shipmentmethods`.`virtuemart_shipmentmethod_id` = `#__virtuemart_orders`.`virtuemart_shipmentmethod_id` AND `virtuemart_order_id` = ' . $virtuemart_order_id ); $shipmentTable = '#__virtuemart_shipment_plg_'. $db->loadResult(); $db->setQuery("DELETE from `". $shipmentTable ."` WHERE `virtuemart_order_id` = " . $virtuemart_order_id); if ($db->execute() === false) { vmError($db->getError()); return false; } else { JPluginHelper::importPlugin('vmshipment'); } } $cart = VirtueMartCart::getCart(); $cart->virtuemart_paymentmethod_id = $_orderData['virtuemart_paymentmethod_id']; $cart->virtuemart_shipmentmethod_id = $_orderData['virtuemart_shipmentmethod_id']; $order['order_status'] = $order['details']['BT']->order_status; $order['customer_notified'] = 0; $order['comments'] = ''; vDispatcher::importVMPlugins('vmpayment'); $returnValues = vDispatcher::trigger('plgVmUpdateOrderHead', array($cart, $order)); return true; } /** Create empty order head record from admin only * * @author Ondřej Spilka * @deprecated * @return ID of the newly created order */ public function CreateOrderHead() { $usrid = 0; $_orderData = new stdClass(); $_orderData->virtuemart_order_id = null; $_orderData->virtuemart_user_id = 0; $_orderData->virtuemart_vendor_id = 1; //TODO $_orderData->order_total = 0; $_orderData->order_salesPrice = 0; $_orderData->order_billTaxAmount = 0; $_orderData->order_billDiscountAmount = 0; $_orderData->order_discountAmount = 0; $_orderData->order_subtotal = 0; $_orderData->order_tax = 0; $_orderData->order_shipment = 0; $_orderData->order_shipment_tax = 0; $_orderData->order_payment = 0; $_orderData->order_payment_tax = 0; $_orderData->order_discount = 0; $_orderData->order_status = 'P'; $_orderData->order_currency = $this->getVendorCurrencyId($_orderData->virtuemart_vendor_id); $_orderData->virtuemart_paymentmethod_id = vRequest::getInt('virtuemart_paymentmethod_id'); $_orderData->virtuemart_shipmentmethod_id = vRequest::getInt('virtuemart_shipmentmethod_id'); //$_orderData->customer_note = ''; $_orderData->ip_address = $_SERVER['REMOTE_ADDR']; $_orderData->order_number =''; JPluginHelper::importPlugin('vmshopper'); $_orderData->order_number = $this->genStdOrderNumber($_orderData->virtuemart_vendor_id); $_orderData->order_pass = $this->genStdOrderPass(); $_orderData->order_create_invoice_pass = $this->genStdCreateInvoicePass(); $orderTable = $this->getTable('orders'); $orderTable -> bindChecknStore($_orderData); $_orderID = $orderTable->virtuemart_order_id;; $_usr = JFactory::getUser(); if (!$this->_writeUserInfo($_orderID, $_usr, array())) { vmError('Problem writing user info to order'); } $orderModel = VmModel::getModel('orders'); $order= $orderModel->getOrder($_orderID); vDispatcher::importVMPlugins('vmpayment'); $cart = VirtueMartCart::getCart(); $returnValues = vDispatcher::trigger('plgVmConfirmedOrder', array($cart, $order)); return $_orderID; } /** * returns true if an invoice number has been created * returns false if an invoice number has not been created due to some configuration parameters */ function createInvoiceNumber($orderDetails, &$invoiceNumber){ $invM = VmModel::getModel('invoice'); return $invM->getExistingIfUnlockedCreateNewInvoiceNumber($orderDetails, $invoiceNumber); } static function getInvoiceNumber($virtuemart_order_id) { VmModel::getModel('invoice'); return VirtueMartModelInvoice::getInvoiceEntry($virtuemart_order_id, true , '`invoice_number`' ); } /** Rename Invoice (when an order is deleted) * * @author Valérie Isaksen * @author Max Milbers * @param $order_id Id of the order * @return boolean true if deleted successful, false if there was a problem */ function renameInvoice($order_id) { $invM = VmModel::getModel('invoice'); return $invM->renameInvoice($order_id); } /** Delete Invoice when an item is updated * * @deprecated * @author Valérie Isaksen * @param $order_id Id of the order * @return boolean true if deleted successful, false if there was a problem */ function deleteInvoice($order_id ) { $invM = VmModel::getModel('invoice'); return $invM->createReferencedInvoiceNumber($order_id); } } // No closing tag