Index: constants.php
===================================================================
--- constants.php (revision 14590)
+++ constants.php (working copy)
@@ -32,7 +32,7 @@
define('PRODUCT_TYPE_DOWNLOADABLE', 4);
define('PRODUCT_TYPE_PACKAGE', 5);
- // payment gateway processing satuses
+ // payment gateway processing statuses
define('SHIPPING_CONTROL_DIRECT', 3);
define('SHIPPING_CONTROL_PREAUTH', 4);
@@ -43,6 +43,51 @@
define('USPS_LABEL_FOLDER', WRITEABLE . '/user_files/labels/');
+ define('ORDER_SHIP_ALL_TOGETHER', 0);
+ define('ORDER_SHIP_BACKORDERS_SEPARATELY', 1);
+ define('ORDER_SHIP_BACKORDERS_UPON_AVAILABLE', 2);
+
+ define('ORDER_GROUP_SHIPPMENTS_AUTO', 0);
+ define('ORDER_GROUP_SHIPPMENTS_MANUAL', 1);
+
+ define('PRODUCT_SHIPPING_MODE_ANY_AND_SELECTED', 0);
+ define('PRODUCT_SHIPPING_MODE_SELECTED_ONLY', 1);
+
+ class OrderCheckoutError {
+ const STATE_CHANGED = 10;
+ const CHANGED_AFTER_LOGIN = 11;
+
+ const QTY_UNAVAILABLE = 20; // orditems:Quantity (users tries to order more, then in stock)
+ const QTY_OUT_OF_STOCK = 21; // orditems:Quantity (product was sold out, after it was added to cart, but before checkout)
+ const QTY_CHANGED_TO_MINIMAL = 22; // orditems:Quantity (qty change to minimal available by price brackets)
+
+ const COUPON_APPLIED = 30; // orditems:ItemData, general
+ const COUPON_REMOVED = 31; // orditems:ItemData, general
+ const COUPON_REMOVED_AUTOMATICALLY = 32; // when discount is more efficient, then coupon being applied
+ const COUPON_CODE_INVALID = 33; // general
+ const COUPON_CODE_EXPIRED = 34; // general
+
+ const GC_APPLIED = 40; // general
+ const GC_REMOVED = 41; // general
+ const GC_REMOVED_AUTOMATICALLY = 42; // general
+ const GC_CODE_INVALID = 43; // general
+ const GC_CODE_EXPIRED = 44; // general
+
+ // new, to integrate
+ const DISCOUNT_APPLIED = 50; // orditems:ItemData, general
+ const DISCOUNT_REMOVED = 51; // orditems:ItemData, general
+
+ const FIELD_UPDATE_SUCCESS = 60; // when order item field is changed + not discount/coupon related
+ const FIELD_UPDATE_ERROR = 61; // when order item field can't be changed + not discount/coupon related
+ }
+
+ class OrderCheckoutErrorType {
+ const PRODUCT = 1;
+ const COUPON = 2;
+ const GIFT_CERTIFICATE = 3;
+ const DISCOUNT = 4;
+ }
+
class ProductInventory {
const DISABLED = 0;
const BY_PRODUCT = 1;
Index: units/coupons/coupons_config.php
===================================================================
--- units/coupons/coupons_config.php (revision 14590)
+++ units/coupons/coupons_config.php (working copy)
@@ -20,18 +20,7 @@
'EventHandlerClass' => Array('class'=>'CouponsEventHandler','file'=>'coupons_event_handler.php','build_event'=>'OnBuild'),
'TagProcessorClass' => Array('class'=>'CouponsTagProcessor','file'=>'coupons_tag_processor.php','build_event'=>'OnBuild'),
'AutoLoad' => true,
- 'Hooks' => Array(
- Array(
- 'Mode' => hBEFORE,
- 'Conditional' => false,
- 'HookToPrefix' => 'ord',
- 'HookToSpecial' => '',
- 'HookToEvent' => Array( 'OnUpdateCart', 'OnCheckout' ),
- 'DoPrefix' => '',
- 'DoSpecial' => '',
- 'DoEvent' => 'OnApplyCoupon',
- ),
- ),
+
'QueryString' => Array(
1 => 'id',
2 => 'Page',
Index: units/coupons/coupons_event_handler.php
===================================================================
--- units/coupons/coupons_event_handler.php (revision 14625)
+++ units/coupons/coupons_event_handler.php (working copy)
@@ -70,28 +70,28 @@
protected function OnBeforeClone(&$event)
{
parent::OnBeforeClone($event);
-
+
$object =& $event->getObject();
/* @var $object kDBItem */
-
+
$this->SetNewCode($object);
-
+
$object->SetDBField('LastUsedBy', NULL);
$object->SetDBField('LastUsedOn', NULL);
$object->SetDBField('NumberOfUses', NULL);
-
+
$expiration = $this->Application->GetVar('clone_coupon_expiration');
$object->SetDBField('Expiration_date', $expiration);
$object->SetDBField('Expiration_time', $expiration);
}
-
+
function OnApplyClone(&$event)
- {
+ {
if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
$event->status = kEvent::erFAIL;
return;
}
-
+
$object =& $event->getObject( Array ('skip_autoload' => true) );
/* @var $object kDBItem */
@@ -106,23 +106,30 @@
$event->status = kEvent::erFAIL;
return ;
}
-
+
$temp =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
/* @var $temp kTempTablesHandler */
-
+
$original_coupon_ids = $this->getSelectedIDs($event, true);
$clone_count = $object->GetDBField('CouponCount');
- $this->Application->StoreVar('CoupLastCloneCount', $clone_count);
+ $this->Application->StoreVar('CoupLastCloneCount', $clone_count);
$this->Application->SetVar('clone_coupon_expiration', $object->GetDBField('DefaultExpiration'));
-
+
for ($i = 0; $i < $clone_count; $i++) {
$temp->CloneItems($event->Prefix, $event->Special, $original_coupon_ids);
}
- $this->finalizePopup($event);
+ $event->SetRedirectParam('opener', 'u');
}
- function setCloningRequired(&$object)
+ /**
+ * Sets fields required during coupon cloning
+ *
+ * @param kDBItem $object
+ * @return void
+ * @access protected
+ */
+ protected function setCloningRequired(&$object)
{
$this->RemoveRequiredFields($object);
$object->setRequired('CouponCount');
@@ -132,7 +139,7 @@
function SetNewCode(&$item)
{
do{
- $new_code = $this->RandomCouponCode(10);
+ $new_code = $this->RandomCouponCode();
$exists = $this->Conn->GetOne('SELECT COUNT(*) FROM '.TABLE_PREFIX.'ProductsCoupons WHERE Code='.$this->Conn->qstr($new_code));
if ($exists){
$new_code = false;
@@ -142,74 +149,16 @@
$item->SetDBField('Code', $new_code);
}
- function RandomCouponCode($size)
+ function RandomCouponCode()
{
- $rand_code = "";
- for ($i=0; $i<10; $i++){
- $is_letter = rand(0,1);
- if ($is_letter){
- $rand_char = chr(rand(65,90));
- }else{
- $rand_char = rand(0,9);
- }
- $rand_code .= $rand_char;
- }
- return $rand_code;
- }
+ $rand_code = '';
- /**
- * Enter description here...
- *
- * @param kEvent $event
- */
- function OnApplyCoupon(&$event)
- {
- $code = $this->Application->GetVar('coupon_code');
- if ($code == '') {
- return ;
+ for ($i = 0; $i < 10; $i++) {
+ $is_letter = rand(0, 1);
+ $rand_code .= ($is_letter ? chr(rand(65, 90)) : rand(0, 9));
}
- $object =& $event->getObject(Array('skip_autoload' => true));
- $object->Load($code, 'Code');
-
- if (!$object->isLoaded()) {
- $event->status = kEvent::erFAIL;
- $this->Application->SetVar('set_checkout_error', 4);
- $event->redirect = false; // check!!!
- return ;
- }
-
- $expire_date = $object->GetDBField('Expiration');
- $number_of_use = $object->GetDBField('NumberOfUses');
- if( $object->GetDBField('Status') != 1 || ($expire_date && $expire_date < adodb_mktime()) ||
- (isset($number_of_use) && $number_of_use <= 0))
- {
- $event->status = kEvent::erFAIL;
- $this->Application->SetVar('set_checkout_error', 5);
- $event->redirect->false;
- return ;
- }
-
- $last_used = adodb_mktime();
- $object->SetDBField('LastUsedBy', $this->Application->RecallVar('user_id'));
- $object->SetDBField('LastUsedOn_date', $last_used);
- $object->SetDBField('LastUsedOn_time', $last_used);
- if(isset($number_of_use))
- {
- $object->SetDBField('NumberOfUses', $number_of_use - 1);
- if($number_of_use == 1)
- {
- $object->SetDBField('Status', 2);
- }
- }
- $object->Update();
-
- $this->Application->setUnitOption('ord', 'AutoLoad', true);
- $order =& $this->Application->recallObject('ord');
- $order->SetDBField('CouponId', $object->GetDBField('CouponId'));
- $order->Update();
-
- $this->Application->SetVar('set_checkout_error', 10);
+ return $rand_code;
}
/**
Index: units/gift_certificates/gift_certificates_config.php
===================================================================
--- units/gift_certificates/gift_certificates_config.php (revision 14590)
+++ units/gift_certificates/gift_certificates_config.php (working copy)
@@ -21,19 +21,6 @@
'TagProcessorClass' => Array ('class' => 'GiftCertificateTagProcessor', 'file' => 'gift_certificates_tp.php', 'build_event' => 'OnBuild'),
'AutoLoad' => true,
- 'Hooks' => Array (
- Array (
- 'Mode' => hBEFORE,
- 'Conditional' => false,
- 'HookToPrefix' => 'ord',
- 'HookToSpecial' => '',
- 'HookToEvent' => Array( 'OnUpdateCart', 'OnCheckout' ),
- 'DoPrefix' => '',
- 'DoSpecial' => '',
- 'DoEvent' => 'OnApplyGiftCertificate',
- ),
- ),
-
'QueryString' => Array (
1 => 'id',
2 => 'Page',
Index: units/gift_certificates/gift_certificates_eh.php
===================================================================
--- units/gift_certificates/gift_certificates_eh.php (revision 14594)
+++ units/gift_certificates/gift_certificates_eh.php (working copy)
@@ -30,47 +30,6 @@
}
/**
- * Enter description here...
- *
- * @param kEvent $event
- */
- function OnApplyGiftCertificate(&$event)
- {
- $code = $this->Application->GetVar('giftcert_code');
- if ($code == '') {
- return ;
- }
-
- $object =& $event->getObject(Array('skip_autoload' => true));
- $object->Load($code, 'Code');
-
- if (!$object->isLoaded()) {
- $event->status = kEvent::erFAIL;
- $this->Application->SetVar('set_checkout_error', 104);
- $event->redirect = false; // check!!!
- return ;
- }
-
- $expire_date = $object->GetDBField('Expiration');
- $debit = $object->GetDBField('Debit');
- if( $object->GetDBField('Status') != 1 || ($expire_date && $expire_date < adodb_mktime()) ||
- ($debit <= 0))
- {
- $event->status = kEvent::erFAIL;
- $this->Application->SetVar('set_checkout_error', 105);
- $event->redirect->false;
- return ;
- }
-
- $this->Application->setUnitOption('ord', 'AutoLoad', true);
- $order =& $this->Application->recallObject('ord');
- $order->SetDBField('GiftCertificateId', $object->GetDBField('GiftCertificateId'));
- $order->Update();
-
- $this->Application->SetVar('set_checkout_error', 110);
- }
-
- /**
* Prepare temp tables for creating new item
* but does not create it. Actual create is
* done in OnPreSaveCreated
Index: units/helpers/helpers_config.php
===================================================================
--- units/helpers/helpers_config.php (revision 0)
+++ units/helpers/helpers_config.php (revision 0)
@@ -0,0 +1,14 @@
+<?php
+
+defined('FULL_PATH') or die('restricted access!');
+
+ $config = Array (
+
+ 'Prefix' => 'in-commerce-helpers',
+
+ 'EventHandlerClass' => Array ('class' => 'kEventHandler', 'file' => '', 'build_event' => 'OnBuild'),
+
+ 'RegisterClasses' => Array (
+ Array ('pseudo' => 'OrderHelper', 'class' => 'OrderHelper', 'file' => 'order_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
+ ),
+ );
Property changes on: units\helpers\helpers_config.php
___________________________________________________________________
Added: svn:keywords
+ Id
Added: svn:eol-style
+ LF
Index: units/helpers/order_helper.php
===================================================================
--- units/helpers/order_helper.php (revision 0)
+++ units/helpers/order_helper.php (revision 0)
@@ -0,0 +1,142 @@
+<?php
+
+ defined('FULL_PATH') or die('restricted access!');
+
+ class OrderHelper extends kHelper
+ {
+ /**
+ * Returns various information about given order
+ *
+ * @param OrdersItem $object
+ * @param string $currency
+ * @param bool $remove_errors
+ * @return Array
+ */
+ function getOrderInfo(&$object, $currency, $remove_errors = true)
+ {
+ $errors = $this->Application->RecallVar('checkout_errors');
+
+ $ret = Array (
+ 'order' => Array (
+ 'CouponId' => (int)$object->GetDBField('CouponId'),
+ 'CouponName' => (string)$object->GetDBField('CouponName'),
+ 'GiftCertificateId' => (int)$object->GetDBField('GiftCertificateDiscount'),
+ 'GiftCertificateDiscount' => $this->convertCurrency($object->GetDBField('GiftCertificateDiscount'), $currency),
+ 'DiscountTotal' => $this->convertCurrency($object->GetDBField('DiscountTotal'), $currency),
+ 'SubTotal' => $this->convertCurrency($object->GetDBField('SubTotal'), $currency),
+ ),
+ 'items' => Array (),
+ 'errors' => $errors ? unserialize($errors) : Array (),
+ );
+
+ $items =& $this->Application->recallObject('orditems', 'orditems_List', Array ('per_page' => -1));
+ /* @var $items kDBList */
+
+ $items->Query();
+ $items->GoFirst();
+
+ if ( $items->EOL() ) {
+ return $ret;
+ }
+
+ $product =& $this->Application->recallObject('p', null, Array ('skip_autoload' => true));
+ /* @var $product kCatDBItem */
+
+ $sql = $product->GetSelectSQL() . '
+ WHERE ' . $product->TableName . '.' . $product->IDField . ' IN (' . implode(',', $items->GetCol('ProductId')) . ')';
+ $products = $this->Conn->Query($sql, $product->IDField);
+
+ while ( !$items->EOL() ) {
+ // prepare product from order item
+ $product->LoadFromHash( $products[ $items->GetDBField('ProductId') ] );
+ $this->Application->SetVar('orditems_id', $items->GetID()); // for edit/delete links using GET
+
+ // weird code from orditems:PrintList
+ $this->Application->SetVar('p_id', $product->GetID());
+ $this->Application->SetVar('m_cat_id', $product->GetDBField('CategoryId'));
+
+ // collect order item info
+ $url_params = Array (
+ 'p_id' => $product->GetID(),
+ 'm_cat_id' => $product->GetDBField('CategoryId'),
+ 'pass' => 'm,p',
+ );
+
+ $product_url = $this->Application->HREF('__default__', '', $url_params);
+
+ $item_data = $items->GetDBField('ItemData');
+ $item_data = $item_data ? unserialize($item_data) : Array ();
+
+ $row_index = $items->GetDBField('ProductId') . ':' . $items->GetDBField('OptionsSalt') . ':' . $items->GetDBField('BackOrderFlag');
+
+ $ret['items'][$row_index] = Array (
+ 'product_url' => $product_url,
+ 'product_type' => $product->GetDBField('Type'),
+ 'options' => isset($item_data['Options']) ? $item_data['Options'] : false,
+ 'free_promo_shipping' => $this->eligibleForFreePromoShipping($items),
+
+ 'fields' => Array (
+ 'OrderItemId' => $items->GetDBField('OrderItemId'),
+ 'ProductName' => $items->GetDBField('ProductName'),
+ 'BackOrderFlag' => (int)$items->GetDBField('BackOrderFlag'),
+ 'FlatPrice' => $this->convertCurrency($items->GetDBField('FlatPrice'), $currency),
+ 'Price' => $this->convertCurrency($items->GetDBField('Price'), $currency),
+ 'Quantity' => (int)$items->GetDBField('Quantity'),
+ 'Virtual' => (int)$items->GetDBField('Virtual'),
+ 'Type' => (int)$product->GetDBField('Type'),
+
+ 'cust_Availability' => $product->GetDBField('cust_Availability'),
+ ),
+ );
+
+ $items->GoNext();
+ }
+
+ if ( $remove_errors ) {
+ $this->Application->RemoveVar('checkout_errors');
+ }
+
+ return $ret;
+ }
+
+ function convertCurrency($amount, $currency)
+ {
+ $converter =& $this->Application->recallObject('kCurrencyRates');
+ /* @var $converter kCurrencyRates */
+
+ // convert primary currency to selected (if they are the same, converter will just return)
+ return (float)$converter->Convert($amount, 'PRIMARY', $this->getISO($currency));
+ }
+
+ function getISO($currency)
+ {
+ if ($currency == 'selected') {
+ $iso = $this->Application->RecallVar('curr_iso');
+ }
+ elseif ($currency == 'primary' || $currency == '') {
+ $iso = $this->Application->GetPrimaryCurrency();
+ }
+ else { //explicit currency
+ $iso = strtoupper($currency);
+ }
+
+ return $iso;
+ }
+
+ /**
+ * Checks, that given order item is eligible for free promo shipping
+ *
+ * @param kDBItem|kDBList $order_item
+ * @return bool
+ */
+ function eligibleForFreePromoShipping(&$order_item)
+ {
+ if ( $order_item->GetDBField('Type') != PRODUCT_TYPE_TANGIBLE ) {
+ return false;
+ }
+
+ $free_shipping = $order_item->GetDBField('MinQtyFreePromoShipping');
+
+ return $free_shipping > 0 && $free_shipping <= $order_item->GetDBField('Quantity');
+ }
+ }
Property changes on: units\helpers\order_helper.php
___________________________________________________________________
Added: svn:keywords
+ Id
Added: svn:eol-style
+ LF
Index: units/order_items/order_items_config.php
===================================================================
--- units/order_items/order_items_config.php (revision 14590)
+++ units/order_items/order_items_config.php (working copy)
@@ -127,6 +127,7 @@
'ItemDiscount' => Array('type'=>'double','formatter'=>'kFormatter','format'=>'%01.2f','default'=>'0.00'),
'SKU' => Array('type' => 'string', 'default' => ''),
'MinQtyFreeShipping'=> Array('type' => 'int', 'default' => 0,),
+ 'Virtual' => Array ('type' => 'int', 'default' => 0),
),
'Grids' => Array (
Index: units/order_items/order_items_event_handler.php
===================================================================
--- units/order_items/order_items_event_handler.php (revision 14625)
+++ units/order_items/order_items_event_handler.php (working copy)
@@ -51,6 +51,7 @@
$product_ids = explode(',', $product_ids);
$product_object =& $this->Application->recallObject('p.-item', null, array('skip_autoload' => true));
+ /* @var $product_object ProductsItem */
foreach ($product_ids as $product_id) {
$product_object->Load($product_id);
@@ -79,7 +80,7 @@
}
}
- $this->finalizePopup($event);
+ $event->SetRedirectParam('opener', 'u');
}
/**
@@ -87,36 +88,131 @@
* Only for "Items" tab in "Orders -> Order Edit" in Admin
*
* @param kEvent $event
+ * @access protected
*/
- function OnUpdate(&$event)
+ protected function OnUpdate(&$event)
{
- parent::OnUpdate($event);
- if ( ($this->Application->GetVar('t') != 'in-commerce/orders/orders_edit_items') ) {
- return true;
+ $items_info = $this->Application->GetVar($event->getPrefixSpecial(true));
+
+ if ( !$items_info ) {
+ return;
}
- $object =& $event->getObject();
+ $object =& $event->getObject(Array ('skip_autoload' => true));
+ /* @var $object kDBItem */
- $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
- if (!$items_info) {
- return ;
+ $table_info = $object->getLinkedInfo();
+
+ $main_object =& $this->Application->recallObject($table_info['ParentPrefix']);
+ /* @var $main_object OrdersItem */
+
+ foreach ($items_info as $id => $field_values) {
+ $object->Clear(); // otherwise validation errors will be passed to next object
+
+ $object->Load($id);
+ $object->SetFieldsFromHash($field_values);
+ $this->customProcessing($event, 'before');
+
+ if ( $object->Update($id) ) {
+ $this->customProcessing($event, 'after');
+ $event->status = kEvent::erSUCCESS;
+ }
+ else {
+ $oi_string = $object->GetDBField('ProductId') . ':' . $object->GetDBField('OptionsSalt') . ':' . $object->GetDBField('BackOrderFlag');
+
+ $field_errors = $object->GetFieldErrors();
+
+ foreach ($field_errors as $field => $error_params) {
+ $error_msg = $object->GetErrorMsg($field);
+
+ if ( $error_msg ) {
+ $main_object->setCheckoutError(OrderCheckoutErrorType::PRODUCT, OrderCheckoutError::FIELD_UPDATE_ERROR, $oi_string . ':' . $field);
+ }
+ }
+
+ $event->status = kEvent::erFAIL;
+ $event->redirect = false;
+// break;
+ }
}
+ if ( $this->Application->GetVar('t') != 'in-commerce/orders/orders_edit_items' ) {
+ return;
+ }
+
$sub_total = $this->getSubTotal($items_info);
- $return_total = $this->getReturnTotal($items_info);
- $table_info = $object->getLinkedInfo();
- $main_object =& $this->Application->recallObject($table_info['ParentPrefix']);
-
- if ($sub_total !== false) {
+ if ( $sub_total !== false ) {
$main_object->SetDBField('SubTotal', $sub_total);
}
- $main_object->SetDBField('ReturnTotal', $return_total);
+ $main_object->SetDBField('ReturnTotal', $this->getReturnTotal($items_info));
$main_object->Update();
}
/**
+ * Remembers what fields were changed
+ *
+ * @param kEvent $event
+ */
+ function OnAfterItemUpdate(&$event)
+ {
+ parent::OnAfterItemUpdate($event);
+
+ if ( $this->Application->isAdmin ) {
+ return ;
+ }
+
+ $object =& $event->getObject();
+ /* @var $object kDBItem */
+
+ $changed_fields = $object->GetChangedFields();
+
+ if ( $changed_fields ) {
+ $table_info = $object->getLinkedInfo();
+
+ $main_object =& $this->Application->recallObject( $table_info['ParentPrefix'] );
+ /* @var $main_object OrdersItem */
+
+ $oi_string = $object->GetDBField('ProductId') . ':' . $object->GetDBField('OptionsSalt') . ':' . $object->GetDBField('BackOrderFlag');
+
+ foreach ($changed_fields as $changed_field => $change_info) {
+ $error_code = OrderCheckoutError::FIELD_UPDATE_SUCCESS;
+
+ if ( $changed_field == 'ItemData' ) {
+ $item_data_old = unserialize( $change_info['old'] );
+ $item_data_new = unserialize( $change_info['new'] );
+
+ if ( $item_data_old['DiscountId'] != $item_data_new['DiscountId'] || $item_data_old['DiscountType'] != $item_data_new['DiscountType'] ) {
+ if ( $item_data_new['DiscountId'] > 0 ) {
+ $error_code = $item_data_new['DiscountType'] == 'discount' ? OrderCheckoutError::DISCOUNT_APPLIED : OrderCheckoutError::COUPON_APPLIED;
+ }
+ else {
+ $error_code = $item_data_old['DiscountType'] == 'discount' ? OrderCheckoutError::DISCOUNT_REMOVED : OrderCheckoutError::COUPON_REMOVED;
+ }
+ }
+
+ if ( $error_code == OrderCheckoutError::DISCOUNT_APPLIED || $error_code == OrderCheckoutError::DISCOUNT_REMOVED ) {
+ // set general error too
+ $main_object->setCheckoutError(OrderCheckoutErrorType::DISCOUNT, $error_code);
+ }
+ }
+ elseif ( $changed_field == 'Quantity' ) {
+ // here is how qty is changed:
+ // OLD QTY -> NEW QTY
+ // RECALCULATE
+ // NEW QTY = IN_STOCK_QTY
+ // NEW ORDER ITEM with LEFTOVER QTY
+ $this->Application->Debugger->appendTrace();
+ $this->Application->Debugger->appendHTML('QTY_CHANGE (' . $oi_string . '): ' . $change_info['old'] . ' => ' . $change_info['new']);
+ }
+
+ $main_object->setCheckoutError(OrderCheckoutErrorType::PRODUCT, $error_code, $oi_string . ':' . $changed_field);
+ }
+ }
+ }
+
+ /**
* Returns subtotal
*
* @param Array $items_info
@@ -193,7 +289,9 @@
$object =& $event->getObject();
/* @var $object kDBItem */
- if ( $item_info = $object->GetDBField('ItemData') ) {
+ $item_info = $object->GetDBField('ItemData');
+
+ if ( $item_info ) {
$item_info = unserialize($item_info);
$object->SetDBField('DiscountType', getArrayValue($item_info, 'DiscountType'));
$object->SetDBField('DiscountId', getArrayValue($item_info, 'DiscountId'));
@@ -213,13 +311,16 @@
parent::SetCustomQuery($event);
$object =& $event->getObject();
+ /* @var $object kDBList */
$package_num = $event->getEventParam('package_num');
- if ($package_num) $object->addFilter('package_num', 'PackageNum = '.$package_num);
+ if ( $package_num ) {
+ $object->addFilter('package_num', 'PackageNum = ' . $package_num);
+ }
$type = $event->getEventParam('product_type');
- if ($type) {
- $object->addFilter('product_type', 'p.Type ='.$type);
+ if ( $type ) {
+ $object->addFilter('product_type', 'p.Type =' . $type);
}
}
@@ -231,19 +332,21 @@
*/
function checkItemStatus(&$event)
{
- if ($this->Application->IsAdmin()) {
+ if ( $this->Application->isAdmin ) {
return true;
}
$object =& $event->getObject();
- if (!$object->isLoaded()) {
+ /* @var $object kDBItem */
+
+ if ( !$object->isLoaded() ) {
return true;
}
$order =& $this->Application->recallObject('ord');
/* @var $order kDBItem */
- if ($order->isLoaded() && ($order->GetID() == $object->GetDBField('OrderId'))) {
+ if ( $order->isLoaded() && ($order->GetID() == $object->GetDBField('OrderId')) ) {
return $order->GetDBField('PortalUserId') == $this->Application->RecallVar('user_id');
}
Index: units/order_items/order_items_tag_processor.php
===================================================================
--- units/order_items/order_items_tag_processor.php (revision 14590)
+++ units/order_items/order_items_tag_processor.php (working copy)
@@ -17,9 +17,10 @@
{
function PrintGrid($params)
{
+ $order =& $this->Application->recallObject('ord');
+ /* @var $order kDBList */
- $order =& $this->Application->recallObject('ord');
- if ($order->GetDBField('Status') != ORDER_STATUS_INCOMPLETE) {
+ if ( $order->GetDBField('Status') != ORDER_STATUS_INCOMPLETE ) {
$params['grid'] = $params['NotEditable'];
}
else {
@@ -29,24 +30,27 @@
return $this->Application->ProcessParsedTag('m', 'ParseBlock', $params);
}
- function IsTangible($params){
- $object =& $this->Application->recallObject( $this->getPrefixSpecial() );
- if ($object->GetDBField('Type') == 1)
- return true;
- else
- return false;
+ function IsTangible($params)
+ {
+ $object =& $this->getObject($params);
+ /* @var $object kDBItem */
+
+ return $object->GetDBField('Type') == PRODUCT_TYPE_TANGIBLE;
}
function HasQty($params)
{
- $object =& $this->Application->recallObject( $this->getPrefixSpecial() );
- $type = $object->GetDBField('Type');
- return in_array($type, array(1,6));
+ $object =& $this->getObject($params);
+ /* @var $object kDBItem */
+
+ return in_array($object->GetDBField('Type'), Array (PRODUCT_TYPE_TANGIBLE, 6));
}
function HasDiscount($params)
{
- $object =& $this->Application->recallObject( $this->getPrefixSpecial() );
+ $object =& $this->getObject($params);
+ /* @var $object kDBItem */
+
return (float)$object->GetDBField('ItemDiscount') ? 1 : 0;
}
@@ -60,31 +64,34 @@
function PrintOptions($params)
{
$object =& $this->getObject($params);
+ /* @var $object kDBItem */
+
$item_data = @unserialize($object->GetDBField('ItemData'));
$render_as = $this->SelectParam($params, 'render_as');
$block_params['name'] = $render_as;
$opt_helper =& $this->Application->recallObject('kProductOptionsHelper');
+ /* @var $opt_helper kProductOptionsHelper */
$o = '';
$options = $item_data['Options'];
foreach ($options as $opt => $val) {
- if (!is_array($val)) {
+ if ( !is_array($val) ) {
$val = kUtil::unhtmlentities($val);
}
$key_data = $opt_helper->ConvertKey($opt, $object->GetDBField('ProductId'));
$parsed = $opt_helper->ExplodeOptionValues($key_data);
- if ($parsed) {
+ if ( $parsed ) {
$values = $parsed['Values'];
$prices = $parsed['Prices'];
$price_types = $parsed['PriceTypes'];
}
else {
- $values = array();
- $prices = array();
- $price_types = array();
+ $values = array ();
+ $prices = array ();
+ $price_types = array ();
}
$key = $key_data['Name'];
@@ -93,10 +100,11 @@
}*/
$lang =& $this->Application->recallObject('lang.current');
+ /* @var $lang LanguagesItem */
- if ($render_as) {
+ if ( $render_as ) {
$block_params['option'] = $key;
- if (is_array($val)) {
+ if ( is_array($val) ) {
$block_params['value'] = $val;
$block_params['type'] = $key_data['OptionType'];
$block_params['price'] = $prices;
@@ -106,9 +114,9 @@
$price_type = array_key_exists($val, $price_types) ? $price_types[$val] : '';
$price = array_key_exists($val, $prices) ? $prices[$val] : '';
- if ($price_type == '$') {
+ if ( $price_type == '$' ) {
$iso = $this->GetISO($params['currency']);
- $value = $this->AddCurrencySymbol($lang->formatNumber($this->ConvertCurrency($price_type, $iso),2), $iso, true); // true to force sign
+ $value = $this->AddCurrencySymbol($lang->formatNumber($this->ConvertCurrency($price_type, $iso), 2), $iso, true); // true to force sign
$block_params['price'] = $value;
$block_params['price_type'] = '';
$block_params['sign'] = ''; // sign is included in the formatted value
@@ -121,10 +129,10 @@
$block_params['value'] = htmlspecialchars($val);
$block_params['type'] = $key_data['OptionType'];
}
- $o.= $this->Application->ParseBlock($block_params, 1);
+ $o .= $this->Application->ParseBlock($block_params, 1);
}
else {
- $o .= $key.': '.$val.'<br>';
+ $o .= $key . ': ' . $val . '<br>';
}
}
return $o;
@@ -158,6 +166,8 @@
$block_params['name'] = $params['render_as'];
$values = $this->Application->Parser->GetParam('value');
+ /* @var $values Array */
+
$prices = $this->Application->Parser->GetParam('price');
$price_types = $this->Application->Parser->GetParam('price_type');
@@ -224,7 +234,7 @@
$this->Application->SetVar('m_cat_id', $product_object->GetDBField('CategoryId'));
- $block_params['is_last'] = ($i == $list->SelectedCount - 1);
+ $block_params['is_last'] = ($i == $list->GetSelectedCount() - 1);
$o.= $this->Application->ParseBlock($block_params, 1);
$list->GoNext();
@@ -242,17 +252,46 @@
function DisplayOptionsPricing($params)
{
$object =& $this->getObject($params);
- if ($object->GetDBField('OptionsSelectionMode') == 1) {
+ /* @var $object kDBItem */
+
+ if ( $object->GetDBField('OptionsSelectionMode') == 1 ) {
return false;
}
$item_data = unserialize($object->GetDBField('ItemData'));
- if (!is_array($item_data)) return false;
+ if ( !is_array($item_data) ) {
+ return false;
+ }
+
$options = getArrayValue($item_data, 'Options');
$helper =& $this->Application->recallObject('kProductOptionsHelper');
+ /* @var $helper kProductOptionsHelper */
+
$crc = $helper->OptionsSalt($options, true);
- $combs = $this->Conn->GetOne('SELECT COUNT(*) FROM '.TABLE_PREFIX.'ProductOptionCombinations WHERE CombinationCRC = '.$crc.' AND ProductId = '.$object->GetDBField('ProductId').' AND (Price != 0 OR (PriceType = 1 AND Price = 0))');
- return $combs == 0; // no overriding combinations found
+ $sql = 'SELECT COUNT(*)
+ FROM ' . TABLE_PREFIX . 'ProductOptionCombinations
+ WHERE CombinationCRC = ' . $crc . ' AND ProductId = ' . $object->GetDBField('ProductId') . ' AND (Price != 0 OR (PriceType = 1 AND Price = 0))';
+
+ return $this->Conn->GetOne($sql) == 0; // no overriding combinations found
}
+
+ function RowIndex($params)
+ {
+ $object =& $this->getObject($params);
+ /* @var $object kDBItem */
+
+ return $object->GetDBField('ProductId') . ':' . $object->GetDBField('OptionsSalt') . ':' . $object->GetDBField('BackOrderFlag');
+ }
+
+ function FreePromoShippingAvailable($params)
+ {
+ $object =& $this->getObject($params);
+ /* @var $object kDBItem */
+
+ $order_helper =& $this->Application->recallObject('OrderHelper');
+ /* @var $order_helper OrderHelper */
+
+ return $order_helper->eligibleForFreePromoShipping($object);
+ }
}
\ No newline at end of file
Index: units/orders/order_calculator.php
===================================================================
--- units/orders/order_calculator.php (revision 14590)
+++ units/orders/order_calculator.php (working copy)
@@ -72,13 +72,17 @@
}
/**
- * Sets error from last operation
+ * Sets checkout error
*
+ * @param int $error_type = {product,coupon,gc}
* @param int $error_code
+ * @param int $product_id - {ProductId}:{OptionsSalt}:{BackOrderFlag}:{FieldName}
+ * @return void
+ * @access protected
*/
- protected function setError($error_code)
+ protected function setError($error_type, $error_code, $product_id = null)
{
- $this->manager->setError($error_code);
+ $this->manager->setError($error_type, $error_code, $product_id);
}
/**
@@ -228,7 +232,12 @@
if ($to_order < $item['Quantity']) {
// ordered less, then requested -> inform user
- $this->setError($to_order > 0 ? 2 : 3);
+ if ( $to_order > 0 ) {
+ $this->setError(OrderCheckoutErrorType::PRODUCT, OrderCheckoutError::QTY_UNAVAILABLE, $item['ProductId'] . ':' . $item['OptionsSalt'] . ':0:Quantity');
+ }
+ else {
+ $this->setError(OrderCheckoutErrorType::PRODUCT, OrderCheckoutError::QTY_OUT_OF_STOCK, $item['ProductId'] . ':' . $item['OptionsSalt'] . ':0:Quantity');
+ }
}
}
}
@@ -364,7 +373,8 @@
if ($qty > 0 && $qty < $min_qty) {
// qty in cart increased to meat minimal qry requirements of given product
- $this->setError(6);
+ $this->setError(OrderCheckoutErrorType::PRODUCT, OrderCheckoutError::QTY_CHANGED_TO_MINIMAL, $item['ProductId'] . ':' . $item['OptionsSalt'] . ':0:Quantity');
+
$item['Quantity'] = $min_qty;
}
}
Index: units/orders/order_manager.php
===================================================================
--- units/orders/order_manager.php (revision 14590)
+++ units/orders/order_manager.php (working copy)
@@ -19,13 +19,6 @@
*/
class OrderManager extends kBase {
- /**
- * Error code from last operation
- *
- * @var int
- */
- protected $errorCode = 0;
-
protected $errorMessages = Array (
1 => 'state_changed',
2 => 'qty_unavailable',
@@ -96,7 +89,6 @@
function reset()
{
- $this->errorCode = 0;
$this->operations = Array ();
$this->totalsOverride = Array ();
@@ -109,23 +101,34 @@
}
/**
- * Sets error from last operation
+ * Sets checkout error
*
+ * @param int $error_type = {product,coupon,gc}
* @param int $error_code
+ * @param int $product_id - {ProductId}:{OptionsSalt}:{BackOrderFlag}:{FieldName}
+ * @return void
+ * @access public
*/
- public function setError($error_code)
+ public function setError($error_type, $error_code, $product_id = null)
{
- $this->errorCode = $error_code;
+ $this->order->setCheckoutError($error_type, $error_code, $product_id);
}
/**
- * Sets error from last operation
+ * Gets error count
*
* @return int
+ * @access public
*/
- public function getError()
+ public function getErrorCount()
{
- return $this->errorCode;
+ $errors = $this->Application->RecallVar('checkout_errors');
+
+ if ( !$errors ) {
+ return 0;
+ }
+
+ return count( unserialize($errors) );
}
/**
@@ -146,7 +149,7 @@
{
$this->calculator->calculate();
- $changed = $this->applyOperations() || ($this->getError() > 0);
+ $changed = $this->applyOperations() || ($this->getErrorCount() > 0);
$this->setOrderTotals();
return $changed;
Index: units/orders/order_validator.php
===================================================================
--- units/orders/order_validator.php (revision 14594)
+++ units/orders/order_validator.php (working copy)
@@ -134,10 +134,10 @@
// Innocent until proven guilty
$cc_valid = true;
- // Get rid of any non-digits
+ // Get rid of any non-digits
$value = preg_replace('/[^\d]/', '', $value);
- // Perform card-specific checks, if applicable
+ // Perform card-specific checks, if applicable
switch( $this->dataSource->GetDBField($cardtype_field) )
{
case 2: // MasterCard
Index: units/orders/orders_config.php
===================================================================
--- units/orders/orders_config.php (revision 14594)
+++ units/orders/orders_config.php (working copy)
@@ -41,18 +41,28 @@
'DoEvent' => 'OnRecalculateItems',
),
- /* OnApplyCoupon is called as hook for OnUpdateCart/OnCheckout, which calls OnRecalcualate themself
- Array (
- 'Mode' => hAFTER,
+ Array(
+ 'Mode' => hBEFORE,
'Conditional' => false,
- 'HookToPrefix' => 'coup',
+ 'HookToPrefix' => '',
'HookToSpecial' => '',
- 'HookToEvent' => Array ( 'OnApplyCoupon' ),
+ 'HookToEvent' => Array( 'OnUpdateCart', 'OnUpdateCartJSON', 'OnCheckout' ),
'DoPrefix' => '',
'DoSpecial' => '',
- 'DoEvent' => 'OnRecalculateItems',
- ),*/
+ 'DoEvent' => 'OnApplyCoupon',
+ ),
+ Array (
+ 'Mode' => hBEFORE,
+ 'Conditional' => false,
+ 'HookToPrefix' => '',
+ 'HookToSpecial' => '',
+ 'HookToEvent' => Array( 'OnUpdateCart', 'OnUpdateCartJSON', 'OnCheckout' ),
+ 'DoPrefix' => '',
+ 'DoSpecial' => '',
+ 'DoEvent' => 'OnApplyGiftCertificate',
+ ),
+
Array (
'Mode' => hAFTER,
'Conditional' => false,
Index: units/orders/orders_event_handler.php
===================================================================
--- units/orders/orders_event_handler.php (revision 14618)
+++ units/orders/orders_event_handler.php (working copy)
@@ -112,6 +112,7 @@
'OnAddToCart' => Array('self' => true),
'OnRemoveFromCart' => Array('self' => true),
'OnUpdateCart' => Array('self' => true),
+ 'OnUpdateCartJSON' => Array('self' => true),
'OnUpdateItemOptions' => Array('self' => true),
'OnCleanupCart' => Array('self' => true),
'OnContinueShopping' => Array('self' => true),
@@ -120,6 +121,7 @@
'OnProceedToBilling' => Array('self' => true),
'OnProceedToPreview' => Array('self' => true),
'OnCompleteOrder' => Array('self' => true),
+ 'OnCombinedPlaceOrder' => Array('self' => true),
'OnRemoveCoupon' => Array('self' => true),
'OnRemoveGiftCertificate' => Array('self' => true),
@@ -161,6 +163,8 @@
function OnQuietPreSave(&$event)
{
$object =& $event->getObject();
+ /* @var $object kDBItem */
+
$object->IgnoreValidation = true;
$event->CallSubEvent('OnPreSave');
$object->IgnoreValidation = false;
@@ -178,6 +182,7 @@
}
$object =& $event->getObject();
+ /* @var $object kDBItem */
$shipping_address_id = $this->Application->GetVar('shipping_address_id');
$billing_address_id = $this->Application->GetVar('billing_address_id');
@@ -294,6 +299,7 @@
$this->Application->registerClass( $gw_data['ClassName'], GW_CLASS_PATH.'/'.$gw_data['ClassFile'] );
$gateway_object =& $this->Application->recallObject( $gw_data['ClassName'] );
+ /* @var $gateway_object kGWBase */
$payment_result = $gateway_object->DirectPayment($order->GetFieldValues(), $gw_data['gw_params']);
$sql = 'UPDATE %s SET GWResult1 = %s WHERE %s = %s';
@@ -319,6 +325,8 @@
function PrepareCoupons(&$event, &$order)
{
$order_items =& $this->Application->recallObject('orditems.-inv','orditems_List',Array('skip_counting'=>true,'per_page'=>-1) );
+ /* @var $order_items kDBList */
+
$order_items->linkToParent($order->Special);
$order_items->Query();
$order_items->GoFirst();
@@ -512,15 +520,11 @@
function OnCheckout(&$event)
{
$this->OnUpdateCart($event);
- if ($event->getEventParam('RecalculateChangedCart'))
- {
- $event->SetRedirectParam('checkout_error', $event->getRedirectParam('checkout_error'));
- }
- else
- {
+ if ( !$event->getEventParam('RecalculateChangedCart') ) {
$object =& $event->getObject();
- if(!$object->HasTangibleItems())
- {
+ /* @var $object OrdersItem */
+
+ if ( !$object->HasTangibleItems() ) {
$object->SetDBField('ShippingTo', '');
$object->SetDBField('ShippingCompany', '');
$object->SetDBField('ShippingPhone', '');
@@ -545,7 +549,10 @@
$event->redirect = $this->Application->GetVar('next_step_template');
$order_id = $this->Application->GetVar('order_id');
- if($order_id !== false) $event->SetRedirectParam('ord_id', $order_id);
+
+ if ( $order_id !== false ) {
+ $event->SetRedirectParam('ord_id', $order_id);
+ }
}
}
@@ -596,10 +603,16 @@
*/
function OnAfterItemUpdate(&$event)
{
+ parent::OnAfterItemUpdate($event);
+
$object =& $event->getObject();
+ /* @var $object OrdersItem */
$cvv2 = $object->GetDBField('PaymentCVV2');
- if($cvv2 !== false) $this->Application->StoreVar('CVV2Code', $cvv2);
+
+ if ( $cvv2 !== false ) {
+ $this->Application->StoreVar('CVV2Code', $cvv2);
+ }
}
@@ -684,6 +697,57 @@
}
/**
+ * Updates cart and returns various info in JSON format
+ *
+ * @param kEvent $event
+ */
+ function OnUpdateCartJSON(&$event)
+ {
+ if ( $this->Application->GetVar('ajax') != 'yes' ) {
+ return;
+ }
+
+ $object =& $event->getObject();
+ /* @var $object kDBItem */
+
+ // 1. delete given order item by id
+ $delete_id = $this->Application->GetVar('delete_id');
+
+ if ( $delete_id !== false ) {
+ $sql = 'DELETE FROM ' . TABLE_PREFIX . 'OrderItems
+ WHERE OrderId = ' . $object->GetID() . ' AND OrderItemId = ' . (int)$delete_id;
+ $this->Conn->Query($sql);
+ }
+
+ // 2. remove coupon
+ $remove = $this->Application->GetVar('remove');
+
+ if ( $remove == 'coupon' ) {
+ $this->RemoveCoupon($object);
+ $object->setCheckoutError(OrderCheckoutErrorType::COUPON, OrderCheckoutError::COUPON_REMOVED);
+ }
+ elseif ( $remove == 'gift_certificate' ) {
+ $this->RemoveGiftCertificate($object);
+ $object->setCheckoutError(OrderCheckoutErrorType::GIFT_CERTIFICATE, OrderCheckoutError::GC_REMOVED);
+ }
+
+ // 3. update product quantities and recalculate all discounts
+ $this->Application->HandleEvent($items_event, 'orditems:OnUpdate');
+ $event->CallSubEvent('OnRecalculateItems');
+
+ // 4. remove "orditems" object of kDBItem class, since getOrderInfo uses kDBList object under same prefix
+ $this->Application->removeObject('orditems');
+
+ $order_helper =& $this->Application->recallObject('OrderHelper');
+ /* @var $order_helper OrderHelper */
+
+ $event->status = kEvent::erSTOP;
+ $currency = $this->Application->GetVar('currency', 'selected');
+
+ echo json_encode( $order_helper->getOrderInfo($object, $currency) );
+ }
+
+ /**
* Adds item to cart
*
* @param kEvent $event
@@ -946,30 +1010,114 @@
return $item_data;
}
+ /**
+ * Enter description here...
+ *
+ * @param kEvent $event
+ */
+ function OnApplyCoupon(&$event)
+ {
+ $code = $this->Application->GetVar('coupon_code');
+
+ if ($code == '') {
+ return ;
+ }
+
+ $object =& $event->getObject();
+ /* @var $object OrdersItem */
+
+ $coupon =& $this->Application->recallObject('coup', null, Array ('skip_autoload' => true));
+ /* @var $coupon kDBItem */
+
+ $coupon->Load($code, 'Code');
+
+ if ( !$coupon->isLoaded() ) {
+ $event->status = kEvent::erFAIL;
+ $object->setCheckoutError(OrderCheckoutErrorType::COUPON, OrderCheckoutError::COUPON_CODE_INVALID);
+ $event->redirect = false; // check!!!
+
+ return ;
+ }
+
+ $expire_date = $coupon->GetDBField('Expiration');
+ $number_of_use = $coupon->GetDBField('NumberOfUses');
+ if ( $coupon->GetDBField('Status') != 1 || ($expire_date && $expire_date < adodb_mktime()) ||
+ (isset($number_of_use) && $number_of_use <= 0))
+ {
+ $event->status = kEvent::erFAIL;
+ $object->setCheckoutError(OrderCheckoutErrorType::COUPON, OrderCheckoutError::COUPON_CODE_EXPIRED);
+ $event->redirect = false;
+
+ return ;
+ }
+
+ $last_used = adodb_mktime();
+ $coupon->SetDBField('LastUsedBy', $this->Application->RecallVar('user_id'));
+ $coupon->SetDBField('LastUsedOn_date', $last_used);
+ $coupon->SetDBField('LastUsedOn_time', $last_used);
+
+
+ if ( isset($number_of_use) ) {
+ $coupon->SetDBField('NumberOfUses', $number_of_use - 1);
+
+ if ($number_of_use == 1) {
+ $coupon->SetDBField('Status', 2);
+ }
+ }
+
+ $coupon->Update();
+
+ $this->Application->setUnitOption('ord', 'AutoLoad', true);
+ $order =& $this->Application->recallObject('ord');
+ /* @var $order OrdersItem */
+
+ $order->SetDBField('CouponId', $coupon->GetDBField('CouponId'));
+ $order->SetDBField('CouponName', $coupon->GetDBField('Name')); // calculated field
+
+ $order->Update();
+
+ $object->setCheckoutError(OrderCheckoutErrorType::COUPON, OrderCheckoutError::COUPON_APPLIED);
+// OnApplyCoupon is called as hook for OnUpdateCart/OnCheckout, which calls OnRecalcualate themself
+ }
+
+ /**
+ * Removes coupon from order
+ *
+ * @param kEvent $event
+ * @deprecated
+ */
function OnRemoveCoupon(&$event)
{
$object =& $event->getObject();
+ /* @var $object OrdersItem */
+
$this->RemoveCoupon($object);
+ $object->setCheckoutError(OrderCheckoutErrorType::COUPON, OrderCheckoutError::COUPON_REMOVED);
+
$event->CallSubEvent('OnRecalculateItems');
- $event->SetRedirectParam('checkout_error', 7);
}
+ /**
+ * Removes coupon from a given order
+ *
+ * @param OrdersItem $object
+ */
function RemoveCoupon(&$object)
{
- $coupon_id = $object->GetDBField('CouponId');
$coupon =& $this->Application->recallObject('coup', null, Array('skip_autoload' => true));
- $res = $coupon->Load($coupon_id);
- $uses = $coupon->GetDBField('NumberOfUses');
+ /* @var $coupon kDBItem */
- if($res && isset($uses))
- {
- $coupon->SetDBField('NumberOfUses', $uses + 1);
- $coupon->SetDBField('Status', 1);
+ $coupon->Load( $object->GetDBField('CouponId') );
+
+ if ( $coupon->isLoaded() ) {
+ $coupon->SetDBField('NumberOfUses', $coupon->GetDBField('NumberOfUses') + 1);
+ $coupon->SetDBField('Status', STATUS_ACTIVE);
$coupon->Update();
}
+
$object->SetDBField('CouponId', 0);
+ $object->SetDBField('CouponName', ''); // calculated field
$object->SetDBField('CouponDiscount', 0);
-
}
/**
@@ -1436,7 +1584,7 @@
}
}
- $this->finalizePopup($event);
+ $event->SetRedirectParam('opener', 'u');
}
function OnMassPlaceOrder(&$event)
@@ -2193,9 +2341,9 @@
*/
function CheckQuantites(&$event)
{
- if ($this->OnRecalculateItems($event)) { // if something has changed in the order
- if ($this->Application->isAdminUser) {
- if ($this->UseTempTables($event)) {
+ if ( $this->OnRecalculateItems($event) ) { // if something has changed in the order
+ if ( $this->Application->isAdminUser ) {
+ if ( $this->UseTempTables($event) ) {
$event->redirect = 'in-commerce/orders/orders_edit_items';
}
}
@@ -2365,18 +2513,20 @@
$ord_id = $order->GetId();
$shipping_option = $order->GetDBField('ShippingOption');
- $backorder_select = $shipping_option == 0 ? '0 As BackOrderFlag' : 'BackOrderFlag';
+ $backorder_select = $shipping_option == 0 ? '0' : 'oi.BackOrderFlag';
// setting PackageNum to 0 for Non-tangible items, for tangibles first package num is always 1
- $query = ' SELECT OrderItemId
- FROM '.$table_prefix.'OrderItems
- LEFT JOIN '.TABLE_PREFIX.'Products
- ON '.TABLE_PREFIX.'Products.ProductId = '.$table_prefix.'OrderItems.ProductId
- WHERE '.TABLE_PREFIX.'Products.Type > 1 AND OrderId = '.$ord_id;
+ $query = ' SELECT oi.OrderItemId
+ FROM ' . $table_prefix . 'OrderItems oi
+ LEFT JOIN ' . TABLE_PREFIX . 'Products p ON p.ProductId = oi.ProductId
+ WHERE p.Type > 1 AND oi.OrderId = ' . $ord_id;
$non_tangibles = $this->Conn->GetCol($query);
+
if ($non_tangibles) {
- $query = 'UPDATE '.$table_prefix.'OrderItems SET PackageNum = 0 WHERE OrderItemId IN ('.implode(',', $non_tangibles).')';
+ $query = ' UPDATE ' . $table_prefix . 'OrderItems
+ SET PackageNum = 0
+ WHERE OrderItemId IN (' . implode(',', $non_tangibles) . ')';
$this->Conn->Query($query);
}
@@ -2386,7 +2536,7 @@
// 2 => ProductId
// 3 => Shipping PackageNum
$query = 'SELECT
- '.$backorder_select.',
+ '.$backorder_select.' AS BackOrderFlagCalc,
PackageNum,
ProductName,
ShippingTypeId,
@@ -2407,8 +2557,8 @@
LEFT JOIN '.TABLE_PREFIX.'Products
ON '.TABLE_PREFIX.'Products.ProductId = '.$table_prefix.'OrderItems.ProductId
WHERE OrderId = '.$ord_id.'
- GROUP BY BackOrderFlag, Grouping
- ORDER BY BackOrderFlag ASC, PackageNum ASC, ProductType ASC';
+ GROUP BY BackOrderFlagCalc, Grouping
+ ORDER BY BackOrderFlagCalc ASC, PackageNum ASC, ProductType ASC';
$sub_orders = $this->Conn->Query($query);
@@ -2474,7 +2624,7 @@
$original_amount = $sub_order->GetDBField('SubTotal') + $sub_order->GetDBField('ShippingCost') + $sub_order->GetDBField('VAT') + $sub_order->GetDBField('ProcessingFee') + $sub_order->GetDBField('InsuranceFee') - $sub_order->GetDBField('GiftCertificateDiscount');
$sub_order->SetDBField('OriginalAmount', $original_amount);
- if ($named_grouping_data['Type'] == 1 && ($sub_order_data['BackOrderFlag'] > 0
+ if ($named_grouping_data['Type'] == 1 && ($sub_order_data['BackOrderFlagCalc'] > 0
||
($sub_order_data['TotalItems'] != $sub_order_data['TotalReserved'])) ) {
$sub_order->SetDBField('Status', ORDER_STATUS_BACKORDERS);
@@ -2500,10 +2650,10 @@
break;
case PRODUCT_TYPE_TANGIBLE:
- $sql = 'SELECT '.$backorder_select.', oi.*
+ $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 (BackOrderFlag = 0) AND (p.Type = '.PRODUCT_TYPE_TANGIBLE.')';
+ WHERE (OrderId = %s) AND (BackOrderFlagCalc = 0) AND (p.Type = '.PRODUCT_TYPE_TANGIBLE.')';
$products = $this->Conn->Query( sprintf($sql, $ord_id) );
foreach ($products as $product) {
@@ -2648,10 +2798,6 @@
$manager->addProduct($product, $event->getEventParam('ItemData'), $qty, $package_num);
$this->Application->HandleEvent($ord_event, 'ord:OnRecalculateItems');
-
- /*if ($ord_event->getEventParam('RecalculateChangedCart') && !$this->Application->isAdmin) {
- $event->SetRedirectParam('checkout_error', $ord_event->getRedirectParam('checkout_error'));
- }*/
}
/**
@@ -2661,30 +2807,25 @@
*/
function UpdateShippingTotal(&$event)
{
- if ($this->Application->GetVar('ebay_notification') == 1) {
+ if ( $this->Application->GetVar('ebay_notification') == 1 ) {
// TODO: get rid of this "if"
- return ;
+ return;
}
+
$object =& $event->getObject();
- $ord_id = $object->GetId();
+ /* @var $object OrdersItem */
- $shipping_option = $object->GetDBField('ShippingOption');
- $backorder_select = $shipping_option == 0 ? '0 As BackOrderFlag' : 'BackOrderFlag';
+ $shipping_total = $insurance_fee = 0;
+ $shipping_info = $object->GetDBField('ShippingInfo') ? unserialize($object->GetDBField('ShippingInfo')) : false;
- $table_prefix = $this->TablePrefix($event);
-
- $shipping_info = $object->GetDBField('ShippingInfo') ? unserialize( $object->GetDBField('ShippingInfo') ) : false;
- $shipping_total = 0;
- $insurance_fee = 0;
- if( is_array($shipping_info) )
- {
- foreach ($shipping_info as $a_shipping)
- {
- // $id_elements = explode('_', $a_shipping['ShippingTypeId']);
+ if ( is_array($shipping_info) ) {
+ foreach ($shipping_info as $a_shipping) {
+// $id_elements = explode('_', $a_shipping['ShippingTypeId']);
$shipping_total += $a_shipping['TotalCost'];
$insurance_fee += $a_shipping['InsuranceFee'];
}
}
+
$object->SetDBField('ShippingCost', $shipping_total);
$object->SetDBField('InsuranceFee', $insurance_fee);
// no need to update, it will be called in calling method
@@ -2693,7 +2834,7 @@
}
/**
- * Recompile shopping cart, splitting or grouping orders and backorders depending on total quantityes.
+ * Recompile shopping cart, splitting or grouping orders and backorders depending on total quantities.
* First it counts total qty for each ProductId, and then creates order for available items
* and backorder for others. It also updates the sub-total for the order
*
@@ -2707,11 +2848,6 @@
return ;
}
- if($checkout_error = $this->Application->GetVar('set_checkout_error'))
- {
- $event->SetRedirectParam('checkout_error', $checkout_error);
- }
-
$order =& $event->getObject();
/* @var $order OrdersItem */
@@ -2734,16 +2870,12 @@
$manager->setOrder($order);
$result = $manager->calculate();
- if ( $manager->getError() ) {
- $event->SetRedirectParam('checkout_error', $manager->getError());
- }
-
- if ($order->GetDBField('CouponId') && $order->GetDBField('CouponDiscount') == 0) {
+ if ( $order->GetDBField('CouponId') && $order->GetDBField('CouponDiscount') == 0 ) {
$this->RemoveCoupon($order);
- $event->SetRedirectParam('checkout_error', 8);
+ $order->setCheckoutError(OrderCheckoutErrorType::COUPON, OrderCheckoutError::COUPON_REMOVED_AUTOMATICALLY);
}
- if ($result) {
+ if ( $result ) {
$this->UpdateShippingOption($event);
}
@@ -2753,26 +2885,25 @@
$this->RecalculateTax($event);
$this->RecalculateGift($event);
- if ($event->Name != 'OnAfterItemUpdate') {
+ if ( $event->Name != 'OnAfterItemUpdate' ) {
$order->Update();
}
$event->setEventParam('RecalculateChangedCart', $result);
- if (is_object($event->MasterEvent)) {
+ if ( is_object($event->MasterEvent) ) {
$event->MasterEvent->setEventParam('RecalculateChangedCart', $result);
}
- if ($result && ($event->getEventParam('checkout_error') === false)) {
- $event->SetRedirectParam('checkout_error', 1);
- }
+ /*if ( $result && !getArrayValue($event->redirect_params, 'checkout_error') ) {
+ $event->SetRedirectParam('checkout_error', OrderCheckoutError::STATE_CHANGED);
+ }*/
- if ($result && is_object($event->MasterEvent) && $event->MasterEvent->Name == 'OnUserLogin')
- {
- if( ($shop_cart_template = $this->Application->GetVar('shop_cart_template'))
- && is_object($event->MasterEvent->MasterEvent) )
- {
- $event->MasterEvent->MasterEvent->SetRedirectParam('checkout_error', 9);
+ if ( $result && is_object($event->MasterEvent) && $event->MasterEvent->Name == 'OnUserLogin' ) {
+ $shop_cart_template = $this->Application->GetVar('shop_cart_template');
+
+ if ( $shop_cart_template && is_object($event->MasterEvent->MasterEvent) ) {
+// $event->MasterEvent->MasterEvent->SetRedirectParam('checkout_error', OrderCheckoutError::CHANGED_AFTER_LOGIN);
$event->MasterEvent->MasterEvent->redirect = $shop_cart_template;
}
}
@@ -3412,12 +3543,67 @@
}
// ===== Gift Certificates Related =====
+ /**
+ * Enter description here...
+ *
+ * @param kEvent $event
+ */
+ function OnApplyGiftCertificate(&$event)
+ {
+ $code = $this->Application->GetVar('giftcert_code');
+
+ if ( $code == '' ) {
+ return;
+ }
+
+ $object =& $event->getObject();
+ /* @var $object OrdersItem */
+
+ $gift_certificate =& $this->Application->recallObject('gc', null, Array ('skip_autoload' => true));
+ /* @var $gift_certificate kDBItem */
+
+ $gift_certificate->Load($code, 'Code');
+
+ if ( !$gift_certificate->isLoaded() ) {
+ $event->status = kEvent::erFAIL;
+ $object->setCheckoutError(OrderCheckoutErrorType::GIFT_CERTIFICATE, OrderCheckoutError::GC_CODE_INVALID);
+ $event->redirect = false; // check!!!
+
+ return;
+ }
+
+ $debit = $gift_certificate->GetDBField('Debit');
+ $expire_date = $gift_certificate->GetDBField('Expiration');
+
+ if ( $gift_certificate->GetDBField('Status') != 1 || ($expire_date && $expire_date < adodb_mktime()) || ($debit <= 0) ) {
+ $event->status = kEvent::erFAIL;
+ $object->setCheckoutError(OrderCheckoutErrorType::GIFT_CERTIFICATE, OrderCheckoutError::GC_CODE_EXPIRED);
+ $event->redirect = false;
+
+ return;
+ }
+
+ $object->SetDBField('GiftCertificateId', $gift_certificate->GetDBField('GiftCertificateId'));
+ $object->Update();
+
+ $object->setCheckoutError(OrderCheckoutErrorType::GIFT_CERTIFICATE, OrderCheckoutError::GC_APPLIED);
+ }
+
+ /**
+ * Removes gift certificate from order
+ *
+ * @param kEvent $event
+ * @deprecated
+ */
function OnRemoveGiftCertificate(&$event)
{
$object =& $event->getObject();
+ /* @var $object OrdersItem */
+
$this->RemoveGiftCertificate($object);
+ $object->setCheckoutError(OrderCheckoutErrorType::GIFT_CERTIFICATE, OrderCheckoutError::GC_REMOVED);
+
$event->CallSubEvent('OnRecalculateItems');
- $event->SetRedirectParam('checkout_error', 107);
}
function RemoveGiftCertificate(&$object)
@@ -3460,6 +3646,8 @@
ini_set('max_execution_time', '0');
$object =& $event->getObject();
+ /* @var $object kDBItem */
+
$file = $object->GetDBField('ShippingTracking') . '.pdf';
$full_path = USPS_LABEL_FOLDER . $file;
@@ -3471,4 +3659,15 @@
header('Content-Disposition: attachment; filename="' . $file . '"');
readfile($full_path);
}
+
+ /**
+ * Enter description here...
+ *
+ * @param kEvent $event
+ */
+ function OnCombinedPlaceOrder(&$event)
+ {
+
+ $event->CallSubEvent('OnUpdate');
+ }
}
\ No newline at end of file
Index: units/orders/orders_item.php
===================================================================
--- units/orders/orders_item.php (revision 14594)
+++ units/orders/orders_item.php (working copy)
@@ -253,8 +253,9 @@
if ($gift_certificate_discount == 0) {
$this->RemoveGiftCertificate($object);
- $event->SetRedirectParam('checkout_error', 108);
+ $this->setCheckoutError(OrderCheckoutErrorType::GIFT_CERTIFICATE, OrderCheckoutError::GC_REMOVED_AUTOMATICALLY);
}
+
$this->SetDBField('GiftCertificateDiscount', $gift_certificate_discount);
}
@@ -278,4 +279,39 @@
$this->SetDBField('GiftCertificateId', 0);
$this->SetDBField('GiftCertificateDiscount', 0);
}
+
+ /**
+ * Sets checkout error
+ *
+ * @param int $error_type = {product,coupon,gc}
+ * @param int $error_code
+ * @param int $product_id - {ProductId}:{OptionsSalt}:{BackOrderFlag}:{FieldName}
+ */
+ function setCheckoutError($error_type, $error_code, $product_id = null)
+ {
+ $errors = $this->Application->RecallVar('checkout_errors');
+ $errors = $errors ? unserialize($errors) : Array ();
+
+ if ( isset($product_id) ) {
+ $error_type .= ':' . $product_id;
+
+ // any error takes priority over FIELD_UPDATE_SUCCESS error
+ if ( isset($errors[$error_type]) && $error_code == OrderCheckoutError::FIELD_UPDATE_SUCCESS ) {
+ return ;
+ }
+ }
+
+ if ( is_numeric($error_code) ) {
+ $errors[$error_type] = $error_code;
+ }
+ else {
+ unset($errors[$error_type]);
+ }
+
+ if ( $this->Application->isDebugMode() ) {
+ $this->Application->Debugger->appendHTML('CO_ERROR: ' . $error_type . ' - ' . $error_code);
+ }
+
+ $this->Application->StoreVar('checkout_errors', serialize($errors));
+ }
}
\ No newline at end of file
Index: units/orders/orders_tag_processor.php
===================================================================
--- units/orders/orders_tag_processor.php (revision 14590)
+++ units/orders/orders_tag_processor.php (working copy)
@@ -102,16 +102,23 @@
$params['render_as'] = $params['item_render_as'];
$tag_params = array_merge($params, Array ('per_page' => -1));
- $o_items = $this->Application->ProcessParsedTag(rtrim('orditems.'.$this->Special, '.'), 'PrintList', $tag_params);
+ $o_items = $this->Application->ProcessParsedTag(rtrim('orditems.' . $this->Special, '.'), 'PrintList', $tag_params);
- if ($o_items) {
- $cart_params = array('name' => $params['header_render_as']);
- $o = $this->Application->ParseBlock($cart_params);
+ if ( $o_items ) {
+ if ( isset($params['header_render_as']) ) {
+ $cart_params = array ('name' => $params['header_render_as']);
+ $o .= $this->Application->ParseBlock($cart_params);
+ }
+
$o .= $o_items;
- $cart_params = array('name' => $params['footer_render_as']);
- $o .= $this->Application->ParseBlock($cart_params);
- } else {
- $cart_params = array('name' => $params['empty_cart_render_as']);
+
+ if ( isset($params['footer_render_as']) ) {
+ $cart_params = array ('name' => $params['footer_render_as']);
+ $o .= $this->Application->ParseBlock($cart_params);
+ }
+ }
+ elseif ( isset($params['empty_cart_render_as']) ) {
+ $cart_params = array ('name' => $params['empty_cart_render_as']);
$o = $this->Application->ParseBlock($cart_params);
}
@@ -203,7 +210,7 @@
return $this->CartNotEmpty($params) ? false : true;
}
- function CartHasBackorders($params)
+ function CartHasBackorders($params = Array ())
{
$object =& $this->getObject($params);
@@ -219,63 +226,82 @@
function PrintShippings($params)
{
$o = '';
+ $limitations_cache = Array ();
+
$object =& $this->getObject($params);
- $ord_id = $object->GetId();
+ /* @var $object kDBItem */
- $shipping_option = $object->GetDBField('ShippingOption');
- $backorder_select = $shipping_option == 0 ? '0 As BackOrderFlag' : 'BackOrderFlag';
+ $ord_id = $object->GetID();
+ $oi_table = $this->Application->getUnitOption('orditems', 'TableName');
- $order_items =& $this->Application->recallObject('orditems', 'orditems_List', Array('skip_autoload' => true) );
- $oi_table = $order_items->TableName;
+ if ( $object->IsTempTable() ) {
+ $oi_table = $this->Application->GetTempName($oi_table, 'prefix' . $object->Prefix);
+ }
- list($split_shipments, $limit_types) = $this->GetShippingLimitations($ord_id);
- foreach ($split_shipments as $group => $data)
- {
- $query = 'UPDATE '.$oi_table.' SET SplitShippingGroup = '.$group.'
- WHERE ProductId IN ('.implode(',', $data['Products']).')';
- $this->Conn->Query($query);
+ list ($split_shipments, $limit_types) = $this->GetShippingLimitations($ord_id);
+
+ foreach ($split_shipments as $group => $data) {
+ $sql = 'UPDATE ' . $oi_table . '
+ SET SplitShippingGroup = ' . $group . '
+ WHERE ProductId IN (' . implode(',', $data['Products']) . ')';
+ $this->Conn->Query($sql);
+
$limitations_cache[$group] = $data['Types'];
}
+
$shipping_group_option = $object->GetDBField('ShippingGroupOption');
- $shipping_group_select = $shipping_group_option == 0 ? '0 AS SplitShippingGroup' : 'SplitShippingGroup';
- if (count($split_shipments) > 1) {
+ $shipping_group_select = $shipping_group_option == ORDER_GROUP_SHIPPMENTS_AUTO ? '0' : 'oi.SplitShippingGroup';
+
+ if ( count($split_shipments) > 1 ) {
+ // different shipping limitations apply
$this->Application->SetVar('shipping_limitations_apply', 1);
- // different shipping limitations apply
- if ($limit_types == 'NONE') {
+
+ if ( $limit_types == 'NONE' ) {
// order can't be shipped with single shipping type
+ $shipping_group_option = ORDER_GROUP_SHIPPMENTS_MANUAL;
+ $shipping_group_select = 'oi.SplitShippingGroup';
$this->Application->SetVar('shipping_limitations_apply', 2);
- $shipping_group_select = 'SplitShippingGroup';
- $shipping_group_option = 1;
}
}
else {
$this->Application->SetVar('shipping_limitations_apply', 0);
}
+
+
+
+ $shipping_option = $object->GetDBField('ShippingOption');
+
$weight_sql = 'IF(oi.Weight IS NULL, 0, oi.Weight * oi.Quantity)';
- $query = 'SELECT
- '.$backorder_select.',
- oi.ProductName,
- oi.ShippingTypeId,
- SUM(oi.Quantity) AS TotalItems,
- SUM('.$weight_sql.') AS TotalWeight,
- SUM(oi.Price * oi.Quantity) AS TotalAmount,'.
- // calculate free Totals => SUM(ALL) - SUM(PROMO) '
- 'SUM(oi.Quantity) - SUM(IF(p.MinQtyFreePromoShipping > 0 AND p.MinQtyFreePromoShipping <= oi.Quantity, oi.Quantity, 0)) AS TotalItemsPromo,
- SUM('.$weight_sql.') - SUM(IF(p.MinQtyFreePromoShipping > 0 AND p.MinQtyFreePromoShipping <= oi.Quantity, '.$weight_sql.', 0)) AS TotalWeightPromo,
- SUM(oi.Price * oi.Quantity) - SUM(IF(p.MinQtyFreePromoShipping > 0 AND p.MinQtyFreePromoShipping <= oi.Quantity, oi.Price * oi.Quantity, 0)) AS TotalAmountPromo,
- '.$shipping_group_select.'
- FROM '.$oi_table.' oi
- LEFT JOIN '.$this->Application->getUnitOption('p', 'TableName').' p
- ON oi.ProductId = p.ProductId
- WHERE oi.OrderId = '.$ord_id.' AND p.Type = 1
- GROUP BY BackOrderFlag, SplitShippingGroup
- ORDER BY BackOrderFlag ASC, SplitShippingGroup ASC';
- $shipments = $this->Conn->Query($query);
+ $sql = 'SELECT
+ ' . ($shipping_option == ORDER_SHIP_ALL_TOGETHER ? '0' : 'oi.BackOrderFlag') . ' AS BackOrderFlagCalc,
+ oi.ProductName,
+ oi.ShippingTypeId,
- $block_params = Array();
+ SUM(oi.Quantity) AS TotalItems,
+ SUM(' . $weight_sql . ') AS TotalWeight,
+ SUM(oi.Price * oi.Quantity) AS TotalAmount,
+
+ SUM(oi.Quantity) - SUM(IF(p.MinQtyFreePromoShipping > 0 AND p.MinQtyFreePromoShipping <= oi.Quantity, oi.Quantity, 0)) AS TotalItemsPromo,
+ SUM(' . $weight_sql . ') - SUM(IF(p.MinQtyFreePromoShipping > 0 AND p.MinQtyFreePromoShipping <= oi.Quantity, ' . $weight_sql . ', 0)) AS TotalWeightPromo,
+ SUM(oi.Price * oi.Quantity) - SUM(IF(p.MinQtyFreePromoShipping > 0 AND p.MinQtyFreePromoShipping <= oi.Quantity, oi.Price * oi.Quantity, 0)) AS TotalAmountPromo,
+
+ ' . $shipping_group_select . ' AS SplitShippingGroupCalc
+ FROM ' . $oi_table . ' oi
+ LEFT JOIN ' . TABLE_PREFIX . 'Products p ON oi.ProductId = p.ProductId
+ WHERE oi.OrderId = ' . $ord_id . ' AND p.Type = ' . PRODUCT_TYPE_TANGIBLE . '
+ GROUP BY BackOrderFlagCalc, SplitShippingGroupCalc
+ ORDER BY BackOrderFlagCalc ASC, SplitShippingGroupCalc ASC';
+ $shipments = $this->Conn->Query($sql);
+
+
+
+
+
+
+ $block_params = Array ();
$block_params['name'] = $this->SelectParam($params, 'render_as,block');
$block_params['user_country_id'] = $object->GetDBField('ShippingCountry');
$block_params['user_state_id'] = $object->GetDBField('ShippingState');
@@ -285,54 +311,51 @@
$block_params['user_addr2'] = $object->GetDBField('ShippingAddress2');
$block_params['user_name'] = $object->GetDBField('ShippingTo');
- if( ($block_params['user_addr1'] == '' || $block_params['user_city'] == '' ||
- $block_params['user_zip'] == '' || $block_params['user_country_id'] == '') &&
- getArrayValue($params, 'invalid_address_render_as'))
- {
- $block_params['name'] = $params['invalid_address_render_as'];
- return $this->Application->ParseBlock($block_params);
- }
-
$group = 1;
foreach ($shipments as $shipment) {
- $where = array('OrderId = '.$ord_id);
- if ($shipping_group_option != 0) {
- $where[] = 'SplitShippingGroup = '.$shipment['SplitShippingGroup'];
+ $where = Array ('OrderId = ' . $ord_id);
+
+ if ( $shipping_group_option == ORDER_GROUP_SHIPPMENTS_MANUAL ) {
+ $where[] = 'SplitShippingGroup = ' . $shipment['SplitShippingGroupCalc'];
}
- if ($shipping_option > 0) { // not all together
- $where[] = 'BackOrderFlag = '.$shipment['BackOrderFlag'];
+
+ if ( $shipping_option != ORDER_SHIP_ALL_TOGETHER ) {
+ $where[] = 'BackOrderFlag = ' . $shipment['BackOrderFlagCalc'];
}
- $query = 'UPDATE '.$oi_table.' SET PackageNum = '.$group.'
- '.($where ? 'WHERE '.implode(' AND ', $where) : '');
- $this->Conn->Query($query);
+ $sql = 'UPDATE ' . $oi_table . '
+ SET PackageNum = ' . $group . '
+ WHERE ' . implode(' AND ', $where);
+ $this->Conn->Query($sql);
+
$group++;
}
+
+ $group = 1;
$this->Application->RemoveVar('LastShippings');
- $group = 1;
$this->Application->SetVar('ShipmentsExists', 1);
+
foreach ($shipments as $shipment) {
+ $block_params['package_num'] = $group;
+ $block_params['limit_types'] = $shipping_group_option == ORDER_GROUP_SHIPPMENTS_AUTO ? $limit_types : $limitations_cache[ $shipment['SplitShippingGroupCalc'] ];
+ $this->Application->SetVar('ItemShipmentsExists', 1); // also set from Order_PrintShippingTypes tag
- $block_params['package_num'] = $group;
-
- $block_params['limit_types'] = strpos($shipping_group_select, '0 AS') !== false ? $limit_types : $limitations_cache[$shipment['SplitShippingGroup']];
-
- $this->Application->SetVar('ItemShipmentsExists', 1);
-
- switch ($shipment['BackOrderFlag']) {
+ switch ( $shipment['BackOrderFlagCalc'] ) {
case 0:
- if ( $this->CartHasBackOrders(Array()) && $shipping_option == 0 ) {
+ if ( $this->CartHasBackOrders() && $shipping_option == ORDER_SHIP_ALL_TOGETHER ) {
$block_params['shipment'] = $this->Application->Phrase('lu_all_available_backordered');
}
else {
$block_params['shipment'] = $this->Application->Phrase('lu_ship_all_available');;
}
break;
+
case 1:
$block_params['shipment'] = $this->Application->Phrase('lu_ship_all_backordered');;
break;
+
default:
$block_params['shipment'] = $this->Application->Phrase('lu_ship_backordered');
break;
@@ -345,133 +368,127 @@
$block_params['weight_metric'] = $shipment['TotalWeight'];
$block_params['weight'] = $shipment['TotalWeight'];
- $regional =& $this->Application->recallObject('lang.current');
- if ($block_params['weight_metric'] == '')
- {
+ if ( $block_params['weight_metric'] == '' ) {
$block_params['weight'] = $this->Application->Phrase('lu_NotAvailable');
}
- elseif ($regional->GetDBField('UnitSystem') == 1)
- {
- $block_params['weight'] .= ' '.$this->Application->Phrase('lu_kg');
+ else {
+ $block_params['weight'] = $this->_formatWeight( $block_params['weight'] );
}
- elseif ($regional->GetDBField('UnitSystem') == 2)
- {
- list($pounds, $ounces) = kUtil::Kg2Pounds($block_params['weight']);
- $block_params['weight'] = $pounds.' '.$this->Application->Phrase('lu_pounds').' '.
- $ounces.' '.$this->Application->Phrase('lu_ounces');
- }
+
$block_params['items'] = $shipment['TotalItems'];
- $iso = $this->GetISO($params['currency']);
- $amount = $this->ConvertCurrency($shipment['TotalAmount'], $iso);
+ $amount = $this->ConvertCurrency($shipment['TotalAmount'], $this->GetISO( $params['currency'] ));
$amount = sprintf("%.2f", $amount);
-// $block_params['amount'] = $this->AddCurrencySymbol($amount, $iso);
$block_params['amount'] = $shipment['TotalAmount'];
- $block_params['field_name'] = $this->InputName(Array('field' => 'ShippingTypeId')).'['.($group).']';
+ $block_params['field_name'] = $this->InputName( Array('field' => 'ShippingTypeId') ) . '[' . $group . ']';
$parsed_block = $this->Application->ParseBlock($block_params);
- if($this->Application->GetVar('ItemShipmentsExists'))
- {
+ if ( $this->Application->GetVar('ItemShipmentsExists') ) {
$o .= $parsed_block;
}
- else
- {
+ else {
$this->Application->SetVar('ShipmentsExists', 0);
- if(getArrayValue($params, 'no_shipments_render_as'))
- {
+
+ if ( getArrayValue($params, 'no_shipments_render_as') ) {
$block_params['name'] = $params['no_shipments_render_as'];
+
return $this->Application->ParseBlock($block_params);
}
}
+
$group++;
}
- if(getArrayValue($params, 'table_header_render_as'))
- {
- $o = $this->Application->ParseBlock( Array('name' => $params['table_header_render_as']) ).$o;
- }
- if(getArrayValue($params, 'table_footer_render_as'))
- {
- $o .= $this->Application->ParseBlock( Array('name' => $params['table_footer_render_as']) );
- }
-
return $o;
}
- function GetShippingLimitations($ord_id)
+ /**
+ * Checks, that all given address fields are valid
+ *
+ * @param Array $params
+ * @return bool
+ */
+ function AddressValid($params)
{
- /*$query = 'SELECT
- c.CachedShippingLimitation
- FROM '.TABLE_PREFIX.'OrderItems AS oi
- LEFT JOIN '.TABLE_PREFIX.'Products AS p
- ON p.ProductId = oi.ProductId
- LEFT JOIN '.TABLE_PREFIX.'CategoryItems AS ci
- ON ci.ItemResourceId = p.ResourceId
- LEFT JOIN '.TABLE_PREFIX.'Category AS c
- ON c.CategoryId = ci.CategoryId
- WHERE
- oi.OrderId = '.$ord_id.'
- AND
- ci.PrimaryCat = 1
- AND
- c.CachedShippingMode = 1;';
- $cat_limitations = $this->Conn->GetCol($query);*/
- $cat_limitations = array();
+ $object =& $this->getObject($params);
+ /* @var $object kDBItem */
- $query = 'SELECT ShippingLimitation, ShippingMode, oi.ProductId as ProductId
- FROM '.TABLE_PREFIX.'Products AS p
- LEFT JOIN '.TABLE_PREFIX.'OrderItems AS oi ON
- oi.ProductId = p.ProductId
- WHERE oi.OrderId = '.$ord_id.' AND p.Type = 1'; // .' AND p.ShippingMode = 1';
- $limitations = $this->Conn->Query($query, 'ProductId');
+ $address_type = isset($params['type']) ? strtolower($params['type']) : 'shipping';
+ $address_type = ucfirst($address_type);
- $split_shipments = array();
+ $check_fields = Array ('Address1', 'City', 'Zip', 'Country');
+ foreach ($check_fields as $check_field) {
+ if ( $object->GetDBField($address_type . $check_field) == '' ) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ function GetShippingLimitations($ord_id)
+ {
$limit = false;
+ $types_index = $split_shipments = $cat_limitations = Array ();
- $types_index = array();
+ $sql = 'SELECT p.ShippingLimitation, p.ShippingMode, oi.ProductId AS ProductId
+ FROM ' . TABLE_PREFIX . 'Products p
+ LEFT JOIN ' . TABLE_PREFIX . 'OrderItems AS oi ON oi.ProductId = p.ProductId
+ WHERE oi.OrderId = ' . $ord_id . ' AND p.Type = ' . PRODUCT_TYPE_TANGIBLE;
+ $limitations = $this->Conn->Query($sql, 'ProductId');
- // group products by shipping type range and caculate intersection of all types available for ALL products
- // the intersaction caclulation is needed to determine if the order can be shipped with single type or not
+ // group products by shipping type range and calculate intersection of all types available for ALL products
+ // the intersection calculation is needed to determine if the order can be shipped with single type or not
+
if ($limitations) {
- $limit_types = null;
- foreach ($limitations as $product_id => $row)
- {
+ $limit_types = false;
+
+ foreach ($limitations as $product_id => $row) {
// if shipping types are limited - get the types
- $types = $row['ShippingLimitation'] != '' ? explode('|', substr($row['ShippingLimitation'], 1, -1)) : array('ANY');
+ $types = $row['ShippingLimitation'] != '' ? explode('|', substr($row['ShippingLimitation'], 1, -1)) : Array ('ANY');
+
// if shipping is NOT limited to selected types (default - so products with no limitations at all also counts)
- if ($row['ShippingMode'] == 0) {
+ if ($row['ShippingMode'] == PRODUCT_SHIPPING_MODE_ANY_AND_SELECTED) {
array_push($types, 'ANY'); // can be shipped with ANY (literally) type
$types = array_unique($types);
}
+
//adding product id to split_shipments group by types range
$i = array_search(serialize($types), $types_index);
if ($i === false) {
$types_index[] = serialize($types);
- $i = count($types_index)-1;
+ $i = count($types_index) - 1;
}
+
$split_shipments[$i]['Products'][] = $product_id;
$split_shipments[$i]['Types'] = serialize($types);
- if ($limit_types == null) { //it is null only when we process first item with limitations
- $limit_types = $types; //initial scope
+
+ if ($limit_types === false) {
+ // it is false only when we process first item with limitations
+ $limit_types = $types; // initial scope
}
// this is to avoid ANY intersect CUST_1 = (), but allows ANY intersect CUST_1,ANY = (ANY)
- if (in_array('ANY', $limit_types) && !in_array('ANY', $types)) {
+ if ( in_array('ANY', $limit_types) && !in_array('ANY', $types) ) {
array_splice($limit_types, array_search('ANY', $limit_types), 1, $types);
}
+
// this is to avoid CUST_1 intersect ANY = (), but allows CUST_1 intersect CUST_1,ANY = (ANY)
- if (!in_array('ANY', $limit_types) && in_array('ANY', $types)) {
+ if ( !in_array('ANY', $limit_types) && in_array('ANY', $types) ) {
array_splice($types, array_search('ANY', $types), 1, $limit_types);
}
+
$limit_types = array_intersect($limit_types, $types);
}
+
$limit_types = count($limit_types) > 0 ? serialize(array_unique($limit_types)) : 'NONE';
}
- return array($split_shipments, $limit_types);
+
+ return Array ($split_shipments, $limit_types);
}
function PaymentTypeForm($params)
@@ -915,33 +932,132 @@
function CartHasError($params)
{
- return $this->Application->GetVar('checkout_error') > 0;
+ return $this->Application->RecallVar('checkout_errors');
}
function CheckoutError($params)
{
- $error_codes = Array (
- 1 => 'state_changed',
- 2 => 'qty_unavailable',
- 3 => 'outofstock',
- 4 => 'invalid_code',
- 5 => 'code_expired',
- 6 => 'min_qty',
- 7 => 'code_removed',
- 8 => 'code_removed_automatically',
- 9 => 'changed_after_login',
- 10 => 'coupon_applied',
- 104 => 'invalid_gc_code',
- 105 => 'gc_code_expired',
- 107 => 'gc_code_removed',
- 108 => 'gc_code_removed_automatically',
- 110 => 'gift_certificate_applied',
- );
+ $errors = $this->Application->RecallVar('checkout_errors');
- $error_param = $error_codes[ $this->Application->GetVar('checkout_error') ];
- return $this->Application->Phrase($params[$error_param]);
+ if ( !$errors ) {
+ return '';
+ }
+
+// $this->Application->RemoveVar('checkout_errors');
+ $errors = unserialize($errors);
+
+ if ( isset($errors[OrderCheckoutErrorType::COUPON]) ) {
+ $mapping = Array (
+ OrderCheckoutError::COUPON_APPLIED => 'coupon_applied',
+ OrderCheckoutError::COUPON_REMOVED => 'code_removed',
+ OrderCheckoutError::COUPON_REMOVED_AUTOMATICALLY => 'code_removed_automatically',
+ OrderCheckoutError::COUPON_CODE_INVALID => 'invalid_code',
+ OrderCheckoutError::COUPON_CODE_EXPIRED => 'code_expired',
+ );
+
+ $error_phrase = $mapping[ $errors[OrderCheckoutErrorType::COUPON] ];
+ }
+ elseif ( isset($errors[OrderCheckoutErrorType::GIFT_CERTIFICATE]) ) {
+ $mapping = Array (
+ OrderCheckoutError::GC_APPLIED => 'gift_certificate_applied',
+ OrderCheckoutError::GC_REMOVED => 'gc_code_removed',
+ OrderCheckoutError::GC_REMOVED_AUTOMATICALLY => 'gc_code_removed_automatically',
+ OrderCheckoutError::GC_CODE_INVALID => 'invalid_gc_code',
+ OrderCheckoutError::GC_CODE_EXPIRED => 'gc_code_expired',
+
+ );
+
+ $error_phrase = $mapping[ $errors[OrderCheckoutErrorType::GIFT_CERTIFICATE] ];
+ }
+ else {
+ $mapping = Array (
+ OrderCheckoutError::QTY_UNAVAILABLE => 'qty_unavailable',
+ OrderCheckoutError::QTY_OUT_OF_STOCK => 'outofstock',
+ OrderCheckoutError::QTY_CHANGED_TO_MINIMAL => 'min_qty',
+ );
+
+ foreach ($errors as $error_type => $error_code) {
+ if ( isset($mapping[$error_code]) ) {
+ $error_phrase = $mapping[$error_code];
+ break;
+ }
+ }
+
+ if ( !isset($error_phrase) ) {
+ $error_phrase = 'state_changed'; // 'changed_after_login'
+ }
+ }
+
+ return $this->Application->Phrase( $params[$error_phrase] );
}
+ /**
+ * Returns checkout errors in JSON format
+ *
+ * @param Array $params
+ * @return string
+ */
+ function PrintOrderInfo($params)
+ {
+ $order_helper =& $this->Application->recallObject('OrderHelper');
+ /* @var $order_helper OrderHelper */
+
+ $object =& $this->getObject($params);
+ /* @var $object kDBItem */
+
+ $currency = isset($params['currency']) ? $params['currency'] : 'selected';
+
+ return json_encode( $order_helper->getOrderInfo($object, $currency) );
+ }
+
+ /**
+ * Returns currency mark (%s is $amount placemark)
+ *
+ * @param Array $params
+ * @return string
+ */
+ function CurrencyMask($params)
+ {
+ $iso = $this->GetISO( $params['currency'] );
+
+ return $this->AddCurrencySymbol('%s', $iso);
+ }
+
+ function CheckoutErrorNew($params)
+ {
+ $errors = $this->Application->RecallVar('checkout_errors');
+
+ if ( !$errors ) {
+ return '';
+ }
+
+// $this->Application->RemoveVar('checkout_errors');
+ $errors = unserialize($errors);
+
+ $reflection = new ReflectionClass('OrderCheckoutErrorType');
+ $error_types = $reflection->getConstants();
+
+ $reflection = new ReflectionClass('OrderCheckoutError');
+ $error_codes = $reflection->getConstants();
+
+ $ret = Array ();
+
+ foreach ($errors as $error_type => $error_code) {
+ $error_type = explode(':', $error_type);
+
+ $error_explained = '<strong>' . array_search($error_type[0], $error_types) . '</strong>';
+
+ if ( $error_type[0] == OrderCheckoutErrorType::PRODUCT ) {
+ $error_explained .= ' (ProductId = <strong>' . $error_type[1] . '</strong>; OptionsSalt: <strong>' . $error_type[2] . '</strong>; BackOrderFlag: ' . $error_type[3] . '; Field: <strong>' . $error_type[4] . '</strong>)';
+ }
+
+ $error_explained .= ' - <strong>' . array_search($error_code, $error_codes) . '</strong>';
+ $ret[] = $error_explained;
+ }
+
+ return implode('<br/>', $ret);
+ }
+
function GetFormAction($params)
{
$object =& $this->getObject($params);
@@ -1311,14 +1427,6 @@
return $max <= 0 ? true : $address_list->GetRecordsCount() < $max;
}
- function FreePromoShippingAvailable($params)
- {
- $object =& $this->Application->recallObject('orditems');
- $free_ship = $object->GetDBField('MinQtyFreePromoShipping');
- $tangible = ($object->GetDBField('Type') == 1)? 1 : 0;
- return ($tangible && ($free_ship > 0 && $free_ship <= $object->GetDBField('Quantity')))? 1 : 0;
- }
-
/**
* Creates link for removing coupon or gift certificate
*
@@ -1358,22 +1466,29 @@
return $this->Application->Phrase('lu_NotAvailable');
}
+ return $this->_formatWeight($total_weight);
+ }
+
+ function _formatWeight($weight)
+ {
$regional =& $this->Application->recallObject('lang.current');
+ /* @var $regional kDBItem */
- switch ($regional->GetDBField('UnitSystem')) {
+ switch ( $regional->GetDBField('UnitSystem') ) {
case 1:
// metric system -> add kg sign
- $total_weight .= ' '.$this->Application->Phrase('lu_kg');
+ $weight .= ' ' . $this->Application->Phrase('lu_kg');
break;
case 2:
// uk system -> convert to pounds
- list($pounds, $ounces) = kUtil::Kg2Pounds($total_weight);
- $total_weight = $pounds.' '.$this->Application->Phrase('lu_pounds').' '.$ounces.' '.$this->Application->Phrase('lu_ounces');
+ list ($pounds, $ounces) = kUtil::Kg2Pounds($weight);
+
+ $weight = $pounds . ' ' . $this->Application->Phrase('lu_pounds') . ' ' . $ounces . ' ' . $this->Application->Phrase('lu_ounces');
break;
}
- return $total_weight;
+ return $weight;
}
function InitCatalogTab($params)
@@ -1494,5 +1609,4 @@
return $o;
}
-
}
\ No newline at end of file