Index: branches/5.3.x/units/orders/orders_event_handler.php =================================================================== diff -u -N -r16223 -r16398 --- branches/5.3.x/units/orders/orders_event_handler.php (.../orders_event_handler.php) (revision 16223) +++ branches/5.3.x/units/orders/orders_event_handler.php (.../orders_event_handler.php) (revision 16398) @@ -1,6 +1,6 @@ getUnitConfig(); - $this->Conn->doUpdate($fields_hash, $config->getTableName(), $config->getIDField() . ' = ' . $order_id); + /** @var OrdersItem $object */ + $object = $this->Application->recallObject($event->Prefix . '.-item', null, array('skip_autoload' => true)); + $object->Load($order_id); - $object = $event->getObject(); - /* @var $object kDBItem */ - - // set user id to object, since it will be used during order update from OnRecalculateItems event - $object->SetDBField('PortalUserId', $user->GetID()); + if ( $object->isLoaded() ) { + $object->SetDBFieldsFromHash($fields_hash); + $object->Update(); + } } function isAffiliate($user_id) @@ -348,9 +348,8 @@ { $gw_data = $order->getGatewayData(); - $this->Application->registerClass( $gw_data['ClassName'], GW_CLASS_PATH.'/'.$gw_data['ClassFile'] ); - $gateway_object = $this->Application->recallObject( $gw_data['ClassName'] ); - /* @var $gateway_object kGWBase */ + /** @var kGWBase $gateway_object */ + $gateway_object = $this->Application->recallObject($gw_data['ClassName']); $payment_result = $gateway_object->DirectPayment($order->GetFieldValues(), $gw_data['gw_params']); $sql = 'UPDATE %s SET GWResult1 = %s WHERE %s = %s'; @@ -1585,9 +1584,10 @@ */ function CheckUser($event) { - if ($this->Application->isAdminUser || defined('GW_NOTIFY')) { - // don't check for user in order while processing payment - // gateways, because they can do cross-domain ssl redirects + if ( $this->Application->isAdminUser || defined('GW_NOTIFY') || defined('CRON') ) { + // 1. don't check, when Administrator is editing the order. + // 2. don't check while processing payment gateways, because they can do cross-domain ssl redirects. + // 3. don't check from CRON, because it's like Admin updates orders on other user behalf. return; } @@ -1643,21 +1643,29 @@ { parent::OnBeforeClone($event); + /** @var OrdersItem $object */ $object = $event->getObject(); - /* @var $object OrdersItem */ if ( substr($event->Special, 0, 9) == 'recurring' ) { $object->SetDBField('SubNumber', $object->getNextSubNumber()); - $object->SetDBField('OriginalAmount', 0); // needed in this case ? } else { $this->setNextOrderNumber($event); - $object->SetDBField('OriginalAmount', 0); } - $object->SetDBField('OrderDate', time()); + + $reset_fields = array( + 'OnHold', 'OrderDate', 'ShippingCost', 'ShippingTracking', 'ShippingDate', 'ReturnTotal', + 'OriginalAmount', 'ShippingInfo', 'GWResult1', 'GWResult2', 'AffiliateCommission', + 'ProcessingFee', 'InsuranceFee', + ); + + foreach ( $reset_fields as $reset_field ) { + $field_options = $object->GetFieldOptions($reset_field); + $object->SetDBField($reset_field, $field_options['default']); + } + + $object->SetDBField('OrderIP', $this->Application->getClientIp()); $object->UpdateFormattersSubFields(); - $object->SetDBField('GWResult1', ''); - $object->SetDBField('GWResult2', ''); } function OnReserveItems($event) @@ -2102,9 +2110,8 @@ // charge user for order in case if we user 2step charging (e.g. AUTH_ONLY + PRIOR_AUTH_CAPTURE) $gw_data = $object->getGatewayData(); - $this->Application->registerClass( $gw_data['ClassName'], GW_CLASS_PATH.'/'.$gw_data['ClassFile'] ); - $gateway_object = $this->Application->recallObject( $gw_data['ClassName'] ); - /* @var $gateway_object kGWBase */ + /** @var kGWBase $gateway_object */ + $gateway_object = $this->Application->recallObject($gw_data['ClassName']); $charge_result = $gateway_object->Charge($object->GetFieldValues(), $gw_data['gw_params']); $sql = 'UPDATE %s SET GWResult2 = %s WHERE %s = %s'; @@ -2168,9 +2175,8 @@ $gw_data = $object->getGatewayData(); if ( $gw_data ) { - $this->Application->registerClass( $gw_data['ClassName'], GW_CLASS_PATH . '/' . $gw_data['ClassFile'] ); - $gateway_object = $this->Application->recallObject( $gw_data['ClassName'] ); - + /** @var kGWBase $gateway_object */ + $gateway_object = $this->Application->recallObject($gw_data['ClassName']); $gateway_object->OrderDeclined($object->GetFieldValues(), $gw_data['gw_params']); } } @@ -2222,9 +2228,8 @@ // inform payment gateway that order was shipped $gw_data = $object->getGatewayData(); - $this->Application->registerClass( $gw_data['ClassName'], GW_CLASS_PATH.'/'.$gw_data['ClassFile'] ); - $gateway_object = $this->Application->recallObject( $gw_data['ClassName'] ); - + /** @var kGWBase $gateway_object */ + $gateway_object = $this->Application->recallObject($gw_data['ClassName']); $gateway_object->OrderShipped($object->GetFieldValues(), $gw_data['gw_params']); } else { @@ -2272,22 +2277,19 @@ } /** - * Set next available order number + * Set next available order number. * - * @param kEvent $event + * @param kEvent $event Event. + * + * @return void */ - function setNextOrderNumber($event) + protected function setNextOrderNumber(kEvent $event) { + /** @var OrdersItem $object */ $object = $event->getObject(); - /* @var $object OrdersItem */ - $sql = 'SELECT MAX(Number) - FROM ' . $this->Application->GetLiveName($object->TableName); - $next_order_number = $this->Conn->GetOne($sql) + 1; + $next_order_number = $this->getNextOrderNumber(); - $next_order_number = max($next_order_number, $this->Application->ConfigValue('Comm_Next_Order_Number')); - $this->Application->SetConfigValue('Comm_Next_Order_Number', $next_order_number + 1); - $object->SetDBField('Number', $next_order_number); $object->SetDBField('SubNumber', 0); @@ -2300,6 +2302,63 @@ } /** + * Returns order number to be used next. + * + * @return integer + */ + protected function getNextOrderNumber() + { + $config_table = $this->Application->getUnitConfig('conf')->getTableName(); + $this->Conn->Query('LOCK TABLES ' . $config_table . ' WRITE'); + + $sql = 'UPDATE ' . $config_table . ' + SET VariableValue = VariableValue + 1 + WHERE VariableName = "Comm_Next_Order_Number"'; + $this->Conn->Query($sql); + + $sql = 'SELECT VariableValue + FROM ' . $config_table . ' + WHERE VariableName = "Comm_Next_Order_Number"'; + $next_order_number = $this->Conn->GetOne($sql); + + $this->Conn->Query('UNLOCK TABLES'); + $this->Application->SetConfigValue('Comm_Next_Order_Number', $next_order_number); + + return $next_order_number - 1; + } + + /** + * [HOOK] Ensures, that "Next Order Number" system setting is within allowed limits. + * + * @param kEvent $event Event. + * + * @return void + */ + protected function OnBeforeNextOrderNumberChange(kEvent $event) + { + /** @var kDBItem $system_setting */ + $system_setting = $event->MasterEvent->getObject(); + + $old_value = $system_setting->GetOriginalField('VariableValue'); + $new_value = $system_setting->GetDBField('VariableValue'); + + if ( $system_setting->GetDBField('VariableName') != 'Comm_Next_Order_Number' || $new_value == $old_value ) { + return; + } + + $sql = 'SELECT MAX(Number) + FROM ' . $event->getUnitConfig()->getTableName(); + $next_order_number = (int)$this->Conn->GetOne($sql) + 1; + + if ( $new_value < $next_order_number ) { + $system_setting->SetError('VariableValue', 'value_out_of_range', null, array( + 'min_value' => $next_order_number, + 'max_value' => '∞', + )); + } + } + + /** * Set's new order address based on another address from order (e.g. billing from shipping) * * @param unknown_type $object @@ -2790,7 +2849,7 @@ $ord_id = $order->GetId(); $shipping_option = $order->GetDBField('ShippingOption'); - $backorder_select = $shipping_option == 0 ? '0' : 'oi.BackOrderFlag'; + $backorder_select = $shipping_option == 0 ? '0' : '%s.BackOrderFlag'; // setting PackageNum to 0 for Non-tangible items, for tangibles first package num is always 1 @@ -2813,7 +2872,7 @@ // 2 => ProductId // 3 => Shipping PackageNum $query = 'SELECT - '.$backorder_select.' AS BackOrderFlagCalc, + ' . sprintf($backorder_select, $table_prefix . 'OrderItems') . ' AS BackOrderFlagCalc, PackageNum, ProductName, ShippingTypeId, @@ -2855,9 +2914,15 @@ $sub_order = $this->Application->recallObject('ord.-sub'.$next_sub_number, 'ord'); /* @var $sub_order OrdersItem */ - if ($this->UseTempTables($event) && $next_sub_number == 0) { + if ( $this->UseTempTables($event) && $next_sub_number == 0 ) { $sub_order =& $order; } + else { + foreach ( $order->GetFieldValues() as $field => $value ) { + $sub_order->SetOriginalField($field, $value); + } + } + $sub_order->SetDBFieldsFromHash($order->GetFieldValues()); $sub_order->SetDBField('SubNumber', $next_sub_number); $sub_order->SetDBField('SubTotal', $sub_order_data['TotalAmount']); @@ -2927,10 +2992,10 @@ break; case PRODUCT_TYPE_TANGIBLE: - $sql = 'SELECT '.$backorder_select.' AS BackOrderFlagCalc, oi.* - FROM '.TABLE_PREFIX.'OrderItems oi - LEFT JOIN '.TABLE_PREFIX.'Products p ON p.ProductId = oi.ProductId - WHERE (OrderId = %s) AND (p.Type = '.PRODUCT_TYPE_TANGIBLE.') + $sql = 'SELECT ' . sprintf($backorder_select, 'oi') . ' AS BackOrderFlagCalc, oi.* + FROM ' . TABLE_PREFIX . 'OrderItems oi + LEFT JOIN ' . TABLE_PREFIX . 'Products p ON p.ProductId = oi.ProductId + WHERE (OrderId = %s) AND (p.Type = ' . PRODUCT_TYPE_TANGIBLE . ') HAVING BackOrderFlagCalc = 0'; $products = $this->Conn->Query( sprintf($sql, $ord_id) ); @@ -2958,18 +3023,24 @@ switch ($named_grouping_data['Type']) { case PRODUCT_TYPE_TANGIBLE: - $query = 'UPDATE '.$table_prefix.'OrderItems SET OrderId = %s WHERE OrderId = %s AND PackageNum = %s'; - $query = sprintf($query, $sub_order->GetId(), $ord_id, $sub_order_data['PackageNum']); + $query = ' UPDATE ' . $table_prefix . 'OrderItems + SET OrderId = %s, PackageNum = 1 + WHERE OrderId = %s AND PackageNum = %s'; + $query = sprintf($query, $sub_order->GetID(), $ord_id, $sub_order_data['PackageNum']); break; case PRODUCT_TYPE_DOWNLOADABLE: - $query = 'UPDATE '.$table_prefix.'OrderItems SET OrderId = %s WHERE OrderId = %s AND ProductId IN (%s)'; - $query = sprintf($query, $sub_order->GetId(), $ord_id, implode(',', $product_ids) ); + $query = ' UPDATE ' . $table_prefix . 'OrderItems + SET OrderId = %s, PackageNum = 1 + WHERE OrderId = %s AND ProductId IN (%s)'; + $query = sprintf($query, $sub_order->GetID(), $ord_id, implode(',', $product_ids)); break; default: - $query = 'UPDATE '.$table_prefix.'OrderItems SET OrderId = %s WHERE OrderId = %s AND OrderItemId = %s'; - $query = sprintf($query, $sub_order->GetId(), $ord_id, $named_grouping_data['OrderItemId']); + $query = ' UPDATE ' . $table_prefix . 'OrderItems + SET OrderId = %s, PackageNum = 1 + WHERE OrderId = %s AND OrderItemId = %s'; + $query = sprintf($query, $sub_order->GetID(), $ord_id, $named_grouping_data['OrderItemId']); break; } @@ -2985,7 +3056,7 @@ $processed_sub_orders[] = $sub_order->GetID(); - $next_sub_number++; + $next_sub_number = $sub_order->getNextSubNumber(); $group++; } @@ -3497,7 +3568,10 @@ function OnLoadSelected($event) { $event->setPseudoClass('_List'); - $object = $event->getObject( Array('selected_only' => true) ); + + /** @var kDBList $object */ + $object = $event->getObject(array('selected_only' => true, 'per_page' => -1)); + $event->redirect = false; } @@ -3759,24 +3833,8 @@ { parent::OnBeforeExportBegin($event); - $options = $event->getEventParam('options'); - - $items_list = $this->Application->recallObject($event->Prefix . '.' . $this->Application->RecallVar('export_oroginal_special'), $event->Prefix . '_List'); - /* @var $items_list kDBList */ - - $items_list->SetPerPage(-1); - - if ( $options['export_ids'] != '' ) { - $items_list->AddFilter('export_ids', $items_list->TableName . '.' . $items_list->IDField . ' IN (' . implode(',', $options['export_ids']) . ')'); - } - - $options['ForceCountSQL'] = $items_list->getCountSQL($items_list->GetSelectSQL(true, false)); - $options['ForceSelectSQL'] = $items_list->GetSelectSQL(); - - $event->setEventParam('options', $options); - + /** @var kDBItem $object */ $object = $this->Application->recallObject($event->Prefix . '.export'); - /* @var $object kDBItem */ $object->SetField('Number', 999999); $object->SetField('SubNumber', 999); @@ -3822,6 +3880,8 @@ } foreach ( $this->trackCopiedOrderIDs($event) as $id ) { + $this->Application->removeObject($event->getPrefixSpecial()); + $an_event = new kEvent($this->Prefix . ':Dummy'); $this->Application->SetVar($this->Prefix . '_id', $id); $this->Application->SetVar($this->Prefix . '_mode', ''); // this is to fool ReserveItems to use live table