Example #1
0
 protected function processChangeProductInCart()
 {
     $mode = Tools::getIsset('update') && $this->id_product ? 'update' : 'add';
     if (!$this->id_product) {
         $this->errors[] = Tools::displayError('Product not found', !Tools::getValue('ajax'));
     }
     $product = new Product($this->id_product, true, $this->context->language->id);
     if (!$product->id || !$product->active || !$product->checkAccess($this->context->cart->id_customer)) {
         $this->errors[] = Tools::displayError('This product is no longer available.', !Tools::getValue('ajax'));
         return;
     }
     $qty_factor = 1;
     $ext_qty_factor = 1;
     $ext_prop_quantities = null;
     $id_cart_product = 0;
     $qty_behavior = 0;
     $icp = (int) Tools::getValue('icp');
     $properties = $product->productProperties();
     if ($icp && $this->context->cart->id) {
         $cart_products = $this->context->cart->getProducts();
         if (count($cart_products)) {
             foreach ($cart_products as $cart_product) {
                 if ($icp == (int) $cart_product['id_cart_product']) {
                     $id_cart_product = $icp;
                     if ($mode == 'add') {
                         if (Tools::getValue('qty') != 'default') {
                             $qty_factor = (int) Tools::getValue('qty');
                         }
                         $_POST['qty'] = (double) $cart_product['cart_quantity_fractional'] > 0 ? (double) $cart_product['cart_quantity_fractional'] : ($product->qtyStep() > 0 ? $product->qtyStep() : 1);
                     } elseif ($mode == 'update') {
                         $qty_behavior = PP::qtyBehavior($product, $cart_product['cart_quantity']);
                     }
                     break;
                 }
             }
         }
     } else {
         if ($properties['pp_ext'] == 1 && in_array($properties['pp_ext_policy'], array(0, 2))) {
             $ext_prop_quantities = array();
             $ext_prop_qty_ratio = array();
             if ($properties['pp_ext_policy'] == 2) {
                 $prop = $product->productProp();
                 if ($this->id_product_attribute) {
                     $id_product_attribute = $this->id_product_attribute;
                 } else {
                     if ($product->hasAttributes()) {
                         $id_product_attribute = Product::getDefaultAttribute($product->id);
                     } else {
                         $id_product_attribute = 0;
                     }
                 }
             }
             $positions = count($properties['pp_ext_prop']);
             for ($position = 1; $position <= $positions; $position++) {
                 $pp_ext_prop = $properties['pp_ext_prop'][$position];
                 if ($properties['pp_ext_policy'] == 2) {
                     $q = PP::productProp($prop, $id_product_attribute, $position, 'quantity');
                     if ($q === false) {
                         $q = (double) $pp_ext_prop['default_quantity'];
                     }
                     if ($q <= 0) {
                         $q = 1;
                     }
                 } else {
                     $q = PP::resolveInputQty(Tools::getValue('pp_ext_prop_quantity_' . $position, 'default'), $properties['pp_qty_policy'], $pp_ext_prop['qty_step'], $pp_ext_prop['default_quantity'] > 0 ? $pp_ext_prop['default_quantity'] : 1);
                 }
                 $ext_prop_quantities[$position] = $q;
                 $ext_prop_qty_ratio[$position] = $properties['pp_ext_prop'][$position]['qty_ratio'];
                 if ($q <= 0) {
                     $this->errors[] = Tools::displayError('Quantity not specified.', !Tools::getValue('ajax'));
                 }
                 $min_qty = (double) $pp_ext_prop['minimum_quantity'];
                 if ($min_qty > 0 && $q < $min_qty) {
                     $this->errors[] = Tools::displayError(sprintf('Please specify at least %s for %s', (string) PP::formatQty($min_qty), (string) $pp_ext_prop['property']), !Tools::getValue('ajax'));
                 }
                 $max_qty = (double) $pp_ext_prop['maximum_quantity'];
                 if ($max_qty > 0 && $q > $max_qty) {
                     $this->errors[] = Tools::displayError(sprintf('Please specify no more than %s for %s', (string) PP::formatQty($max_qty), (string) $pp_ext_prop['property']), !Tools::getValue('ajax'));
                 }
             }
             if (!$this->errors) {
                 $ext_qty_factor = $properties['pp_ext_method'] == 1 ? 1 : 0;
                 $positions = count($ext_prop_quantities);
                 for ($position = 1; $position <= $positions; $position++) {
                     $value = $ext_prop_quantities[$position];
                     $qty_ratio = $ext_prop_qty_ratio[$position];
                     if ($properties['pp_ext_method'] == 1) {
                         $ext_qty_factor *= $qty_ratio > 0 ? $value / $qty_ratio : $value;
                     } elseif ($properties['pp_ext_method'] == 2) {
                         $ext_qty_factor += $qty_ratio > 0 ? $value / $qty_ratio : $value;
                     }
                 }
             }
         }
     }
     if (!$this->errors) {
         if ($this->id_product_attribute) {
             $default_quantity = $product->attributeDefaultQty($this->id_product_attribute);
             $this->qty = $qty_factor * $this->resolveInputQty($properties, $default_quantity);
             if ($this->qty == 0) {
                 $this->errors[] = Tools::displayError('Quantity not specified.', !Tools::getValue('ajax'));
             } else {
                 if (!Product::isAvailableWhenOutOfStock($product->out_of_stock) && !Attribute::checkAttributeQty($this->id_product_attribute, $ext_qty_factor * $this->qty)) {
                     $this->errors[] = Tools::displayError('There isn\'t enough product in stock.', !Tools::getValue('ajax'));
                 }
             }
         } else {
             if ($product->hasAttributes()) {
                 $min_quantity = $product->out_of_stock == 2 ? !Configuration::get('PS_ORDER_OUT_OF_STOCK') : !$product->out_of_stock;
                 $this->id_product_attribute = Product::getDefaultAttribute($product->id, $min_quantity);
                 if (!$this->id_product_attribute) {
                     Tools::redirectAdmin($this->context->link->getProductLink($product));
                 } else {
                     $default_quantity = $product->attributeDefaultQty($this->id_product_attribute);
                     $this->qty = $qty_factor * $this->resolveInputQty($properties, $default_quantity);
                     if ($this->qty == 0) {
                         $this->errors[] = Tools::displayError('Quantity not specified.', !Tools::getValue('ajax'));
                     } else {
                         if (!Product::isAvailableWhenOutOfStock($product->out_of_stock) && !Attribute::checkAttributeQty($this->id_product_attribute, $ext_qty_factor * $this->qty)) {
                             $this->errors[] = Tools::displayError('There isn\'t enough product in stock.', !Tools::getValue('ajax'));
                         }
                     }
                 }
             } else {
                 $default_quantity = $product->defaultQty();
                 $this->qty = $qty_factor * $this->resolveInputQty($properties, $default_quantity);
                 if ($this->qty == 0) {
                     $this->errors[] = Tools::displayError('Quantity not specified.', !Tools::getValue('ajax'));
                 } else {
                     if (!$product->checkQty($ext_qty_factor * $this->qty)) {
                         $this->errors[] = Tools::displayError('There isn\'t enough product in stock.', !Tools::getValue('ajax'));
                     }
                 }
             }
         }
     }
     if (!$this->errors && ($mode == 'add' || $mode == 'update' && $qty_behavior)) {
         if ($mode == 'add' && !$this->context->cart->id) {
             if (Context::getContext()->cookie->id_guest) {
                 $guest = new Guest(Context::getContext()->cookie->id_guest);
                 $this->context->cart->mobile_theme = $guest->mobile_theme;
             }
             $this->context->cart->add();
             if ($this->context->cart->id) {
                 $this->context->cookie->id_cart = (int) $this->context->cart->id;
             }
         }
         if (!$product->hasAllRequiredCustomizableFields() && !$this->customization_id) {
             $this->errors[] = Tools::displayError('Please fill in all of the required fields, and then save your customizations.', !Tools::getValue('ajax'));
         }
         if (!$this->errors) {
             $cart_rules = $this->context->cart->getCartRules();
             $update_quantity = $this->context->cart->updateQty($id_cart_product ? $mode == 'add' ? $qty_factor : $this->qty : ($ext_prop_quantities !== null ? $ext_qty_factor : $this->qty), $this->id_product, $this->id_product_attribute, $this->customization_id, $mode == 'update' ? 'update' : Tools::getValue('op', 'up'), $this->id_address_delivery, null, true, $id_cart_product, $ext_prop_quantities, $this->qty);
             if ($update_quantity < 0) {
                 $minimal_quantity = $this->id_product_attribute ? $product->attributeMinQty($this->id_product_attribute) : $product->minQty();
                 $this->errors[] = Tools::displayError(sprintf('You must add %s minimum quantity', $minimal_quantity), !Tools::getValue('ajax'));
             } elseif (!$update_quantity) {
                 $this->errors[] = Tools::displayError('You already have the maximum quantity available for this product.', !Tools::getValue('ajax'));
             } elseif ((int) Tools::getValue('allow_refresh')) {
                 $cart_rules2 = $this->context->cart->getCartRules();
                 if (count($cart_rules2) != count($cart_rules)) {
                     $this->ajax_refresh = true;
                 } else {
                     $rule_list = array();
                     foreach ($cart_rules2 as $rule) {
                         $rule_list[] = $rule['id_cart_rule'];
                     }
                     foreach ($cart_rules as $rule) {
                         if (!in_array($rule['id_cart_rule'], $rule_list)) {
                             $this->ajax_refresh = true;
                             break;
                         }
                     }
                 }
             }
         }
     }
     $removed = CartRule::autoRemoveFromCart();
     CartRule::autoAddToCart();
     if (count($removed) && (int) Tools::getValue('allow_refresh')) {
         $this->ajax_refresh = true;
     }
 }
 public function ajaxProcessUpdateQty()
 {
     if ($this->tabAccess['edit'] === '1') {
         $errors = array();
         if (!$this->context->cart->id) {
             return;
         }
         if ($this->context->cart->OrderExists()) {
             $errors[] = Tools::displayError('An order has already been placed with this cart.');
         } elseif (!($id_product = (int) Tools::getValue('id_product')) || !($product = new Product((int) $id_product, true, $this->context->language->id))) {
             $errors[] = Tools::displayError('Invalid product');
         } elseif (!($qty = Tools::getValue('qty')) || $qty == 0) {
             $errors[] = Tools::displayError('Invalid quantity');
         } else {
             $icp = (int) Tools::getValue('icp');
             if ($icp != 'add' && (!($icp = (int) $icp) || $icp == 0)) {
                 $errors[] = Tools::displayError('Invalid cart product reference');
             }
         }
         if (!count($errors)) {
             // Don't try to use a product if not instanciated before due to errors
             if (isset($product) && $product->id) {
                 $id_product_attribute = Tools::getValue('id_product_attribute');
                 if ($icp == 'add') {
                     $id_cart_product = 0;
                     $properties = $product->productProperties();
                     $qty_policy = $properties['pp_qty_policy'];
                     $qty = PP::resolveInputQty($qty, $qty_policy, $properties['pp_qty_step']);
                     if (PP::qtyPolicyFractional($qty_policy)) {
                         $quantity_fractional = $qty;
                         $qty = 1;
                         $update_qty = $quantity_fractional;
                     } else {
                         $qty = (int) $qty;
                         $quantity_fractional = 0;
                         $update_qty = $qty;
                     }
                 } else {
                     $cart_products = $this->context->cart->getProducts();
                     if (count($cart_products)) {
                         foreach ($cart_products as $cart_product) {
                             if ($icp == (int) $cart_product['id_cart_product']) {
                                 $id_cart_product = $icp;
                                 $qty = (int) $qty;
                                 $quantity_fractional = $cart_product['cart_quantity_fractional'];
                                 $update_qty = $qty;
                                 break;
                             }
                         }
                     }
                 }
                 if (isset($id_cart_product)) {
                     if ($id_product_attribute != 0) {
                         if (!Product::isAvailableWhenOutOfStock($product->out_of_stock) && !Attribute::checkAttributeQty((int) $id_product_attribute, PP::resolveQty($qty, $quantity_fractional))) {
                             $errors[] = Tools::displayError('There is not enough product in stock.');
                         }
                     } else {
                         if (!$product->checkQty(PP::resolveQty($qty, $quantity_fractional))) {
                             $errors[] = Tools::displayError('There is not enough product in stock.');
                         }
                     }
                     if (!($id_customization = (int) Tools::getValue('id_customization', 0)) && !$product->hasAllRequiredCustomizableFields()) {
                         $errors[] = Tools::displayError('Please fill in all required fields.');
                     }
                     $this->context->cart->save();
                 } else {
                     $errors[] = Tools::displayError('This product cannot be added to the cart.');
                 }
             } else {
                 $errors[] = Tools::displayError('This product cannot be added to the cart.');
             }
         }
         if (!count($errors)) {
             if ((int) $update_qty < 0) {
                 $update_qty = str_replace('-', '', $update_qty);
                 $operator = 'down';
             } else {
                 $operator = 'up';
             }
             if (!($qty_upd = $this->context->cart->updateQty($update_qty, $id_product, (int) $id_product_attribute, (int) $id_customization, $operator, 0, null, true, $id_cart_product))) {
                 $errors[] = Tools::displayError('You already have the maximum quantity available for this product.');
             } elseif ($qty_upd < 0) {
                 $minimal_qty = $id_product_attribute ? $product->attributeMinQty((int) $id_product_attribute) : $product->minQty();
                 $errors[] = sprintf(Tools::displayError('You must add a minimum quantity of %d', false), $minimal_qty);
             }
         }
         echo Tools::jsonEncode(array_merge($this->ajaxReturnVars(), array('errors' => $errors)));
     }
 }
Example #3
0
 private function processPrice()
 {
     if ($this->id_product) {
         $product = new Product($this->id_product, true, $this->context->language->id);
         if ($product->id && $product->active) {
             $error = false;
             $properties = $product->productProperties();
             if ($properties['pp_ext'] == 1 && in_array($properties['pp_ext_policy'], array(0, 2))) {
                 $qty = PP::resolveInputQty(Tools::getValue('qty'), 0, $properties['pp_qty_step']);
             } else {
                 $qty = PP::resolveInputQty(Tools::getValue('qty'), $properties['pp_qty_policy'], $properties['pp_qty_step']);
             }
             if ($qty <= 0) {
                 $error = true;
             }
             if (!$error) {
                 if ($properties['pp_ext'] == 1 && in_array($properties['pp_ext_policy'], array(0, 2))) {
                     $ext_prop_quantities = array();
                     $ext_prop_qty_ratio = array();
                     if ($properties['pp_ext_policy'] == 2) {
                         $prop = $product->productProp();
                     }
                     $positions = count($properties['pp_ext_prop']);
                     for ($position = 1; $position <= $positions; $position++) {
                         $pp_ext_prop = $properties['pp_ext_prop'][$position];
                         if ($properties['pp_ext_policy'] == 2) {
                             $q = PP::productProp($prop, $this->id_product_attribute, $position, 'quantity');
                             if ($q === false) {
                                 $q = (double) $pp_ext_prop['default_quantity'];
                             }
                             if ($q <= 0) {
                                 $q = 1;
                             }
                         } else {
                             $q = PP::resolveInputQty(Tools::getValue('pp_ext_prop_quantity_' . $position, 'default'), $properties['pp_qty_policy'], $pp_ext_prop['qty_step'], $pp_ext_prop['default_quantity'] > 0 ? $pp_ext_prop['default_quantity'] : 1);
                         }
                         $ext_prop_quantities[$position] = $q;
                         $ext_prop_qty_ratio[$position] = $properties['pp_ext_prop'][$position]['qty_ratio'];
                         if ($q <= 0) {
                             $error = true;
                         }
                         $min_qty = (double) $pp_ext_prop['minimum_quantity'];
                         if ($min_qty > 0 && $q < $min_qty) {
                             $error = true;
                         }
                         $max_qty = (double) $pp_ext_prop['maximum_quantity'];
                         if ($max_qty > 0 && $q > $max_qty) {
                             $error = true;
                         }
                     }
                     if (!$error) {
                         $ext_prop_qty = array();
                         $quantity = $qty;
                         $quantity_fractional = $properties['pp_ext_method'] == 1 ? 1 : 0;
                         $count = count($ext_prop_quantities);
                         for ($position = 1; $position <= $count; $position++) {
                             $value = $ext_prop_quantities[$position];
                             $qty_ratio = $ext_prop_qty_ratio[$position];
                             $ext_prop_qty[$position] = $qty_ratio > 0 ? $value / $qty_ratio : $value;
                             if ($properties['pp_ext_method'] == 1) {
                                 $quantity_fractional *= $ext_prop_qty[$position];
                             } elseif ($properties['pp_ext_method'] == 2) {
                                 $quantity_fractional += $ext_prop_qty[$position];
                             }
                         }
                     }
                 } else {
                     if (PP::qtyPolicyFractional($properties['pp_qty_policy'])) {
                         $quantity = 1;
                         $quantity_fractional = $qty;
                     } else {
                         $quantity = $qty;
                         $quantity_fractional = 0;
                     }
                 }
             }
             if (!$error) {
                 $id_customer = isset($this->context->customer) ? $this->context->customer->id : null;
                 $this->id_product_attribute = $this->id_product_attribute > 0 ? $this->id_product_attribute : null;
                 $qty = array($quantity, $quantity_fractional);
                 $address = new Address($this->context->cart->{Configuration::get('PS_TAX_ADDRESS_TYPE')});
                 $tax = (double) $product->getTaxesRate($address);
                 $no_tax = Tax::excludeTaxeOption() || !$tax || Group::getPriceDisplayMethod($this->context->customer->id_default_group);
                 $specific_price_output = null;
                 $total = Product::getPriceStatic($this->id_product, !$no_tax, $this->id_product_attribute, 6, null, false, true, $qty, false, $id_customer, null, $address->id, $specific_price_output, true, true, $this->context);
                 $total = PP::calcPrice($total, $quantity, $quantity_fractional, $this->id_product, false);
                 $result = array('status' => 'success', 'total' => &$total);
                 /*[HOOK ppropertiessmartprice]*/
                 $result['total'] = Tools::ps_round($total, _PS_PRICE_COMPUTE_PRECISION_);
             }
         }
     }
     if (!isset($result)) {
         $result = array('status' => 'error');
     }
     die(Tools::jsonEncode($result));
 }
Example #4
0
    public function updateQty($quantity, $id_product, $id_product_attribute = null, $id_customization = false, $operator = 'up', $id_address_delivery = 0, Shop $shop = null, $auto_add_cart_rule = true, $id_cart_product = 0, $ext_prop_quantities = null, $ext_qty = 0)
    {
        if (!$shop) {
            $shop = Context::getContext()->shop;
        }
        if (Context::getContext()->customer->id) {
            if ($id_address_delivery == 0 && (int) $this->id_address_delivery) {
                // The $id_address_delivery is null, use the cart delivery address
                $id_address_delivery = $this->id_address_delivery;
            } elseif ($id_address_delivery == 0) {
                // The $id_address_delivery is null, get the default customer address
                $id_address_delivery = (int) Address::getFirstCustomerAddressId((int) Context::getContext()->customer->id);
            } elseif (!Customer::customerHasAddress(Context::getContext()->customer->id, $id_address_delivery)) {
                // The $id_address_delivery must be linked with customer
                $id_address_delivery = 0;
            }
        }
        //$quantity = (int)$quantity;
        $id_product = (int) $id_product;
        $id_product_attribute = (int) $id_product_attribute;
        $product = new Product($id_product, false, Configuration::get('PS_LANG_DEFAULT'), $shop->id);
        if ($id_product_attribute) {
            $combination = new Combination((int) $id_product_attribute);
            if ($combination->id_product != $id_product) {
                return false;
            }
        }
        $properties = $product->productProperties();
        $quantity = $product->normalizeQty($quantity);
        /* If we have a product combination, the minimal quantity is set with the one of this combination */
        if (!empty($id_product_attribute)) {
            $minimal_quantity = $product->attributeMinQty($id_product_attribute);
        } else {
            $minimal_quantity = $product->minQty();
        }
        if (!Validate::isLoadedObject($product)) {
            die(Tools::displayError());
        }
        if (isset(self::$_nbProducts[$this->id])) {
            unset(self::$_nbProducts[$this->id]);
        }
        if (isset(self::$_totalWeight[$this->id])) {
            unset(self::$_totalWeight[$this->id]);
        }
        Hook::exec('actionBeforeCartUpdateQty', array('cart' => $this, 'product' => $product, 'id_product_attribute' => $id_product_attribute, 'id_customization' => $id_customization, 'quantity' => $quantity, 'operator' => $operator, 'id_address_delivery' => $id_address_delivery, 'shop' => $shop, 'auto_add_cart_rule' => $auto_add_cart_rule));
        if ($quantity <= 0) {
            return $this->deleteProduct($id_product, $id_product_attribute, (int) $id_customization, 0, $id_cart_product);
        } elseif (!$product->available_for_order || Configuration::get('PS_CATALOG_MODE') && !defined('_PS_ADMIN_DIR_')) {
            return false;
        } else {
            if ($id_cart_product == 0 && !PP::qtyPolicyLegacy($properties['pp_qty_policy'])) {
                $result = false;
            } else {
                /* Check if the product is already in the cart */
                $result = $this->containsProduct($id_product, $id_product_attribute, (int) $id_customization, (int) $id_address_delivery, PP::productQtyPolicyLegacy($product) ? 0 : $quantity, $id_cart_product);
            }
            /* Update quantity if product already exist */
            if ($result) {
                if ($operator == 'up' || $operator == 'update') {
                    $sql = 'SELECT stock.out_of_stock, IFNULL(stock.quantity, 0) as quantity, IFNULL(stock.quantity_remainder, 0) as quantity_remainder
							FROM ' . _DB_PREFIX_ . 'product p
							' . Product::sqlStock('p', $id_product_attribute, true, $shop) . '
							WHERE p.id_product = ' . $id_product;
                    $result2 = Db::getInstance()->getRow($sql);
                    $product_qty = (int) $result2['quantity'] + (double) $result2['quantity_remainder'];
                    // Quantity for product pack
                    if (Pack::isPack($id_product)) {
                        $product_qty = Pack::getQuantity($id_product, $id_product_attribute);
                    }
                    if ($operator == 'up') {
                        $q = $id_cart_product > 0 || PP::qtyPolicyLegacy($properties['pp_qty_policy']) ? (int) $quantity : 1;
                        $new_qty = PP::resolveQty((int) $result['quantity'] + $q, $result['quantity_fractional']);
                        $new_min_qty = $properties['pp_ext'] == 1 ? (int) $result['quantity'] + $q : $new_qty;
                        $qty = '+ ' . (int) $q;
                    } else {
                        $new_qty = $new_min_qty = $qty = $quantity;
                    }
                    if (!Product::isAvailableWhenOutOfStock((int) $result2['out_of_stock'])) {
                        if ($new_qty > $product_qty) {
                            return false;
                        }
                    }
                } else {
                    if ($operator == 'down') {
                        $q = $id_cart_product > 0 ? (int) $quantity : 1;
                        $new_qty = PP::resolveQty((int) $result['quantity'] - $q, $result['quantity_fractional']);
                        $new_min_qty = $properties['pp_ext'] == 1 ? (int) $result['quantity'] - $q : $new_qty;
                        $qty = '- ' . (int) $q;
                        if ($new_min_qty < $minimal_quantity && (PP::qtyPolicyLegacy($properties['pp_qty_policy'] || $properties['pp_ext'] == 1) ? $minimal_quantity > 1 : $new_qty > 0)) {
                            return -1;
                        }
                    } else {
                        return false;
                    }
                }
                /* Delete product from cart */
                if (($properties['pp_ext'] == 1 ? $new_min_qty : $new_qty) <= 0) {
                    return $this->deleteProduct((int) $id_product, (int) $id_product_attribute, (int) $id_customization, $id_address_delivery, $id_cart_product);
                } else {
                    if ($new_min_qty < $minimal_quantity) {
                        return -1;
                    } else {
                        if ($operator == 'up' || $operator == 'down') {
                            Db::getInstance()->execute('
								UPDATE `' . _DB_PREFIX_ . 'cart_product`
								SET `quantity` = `quantity` ' . $qty . ', `date_add` = NOW()
								WHERE `id_cart_product` = ' . (int) $result['id_cart_product'] . '
								LIMIT 1');
                        } else {
                            Db::getInstance()->execute('
							UPDATE `' . _DB_PREFIX_ . 'cart_product`
							SET `quantity_fractional` = ' . $qty . ', `date_add` = NOW()
							WHERE `id_cart_product` = ' . (int) $result['id_cart_product'] . '
							LIMIT 1');
                        }
                    }
                }
                $id_cart_product = (int) $result['id_cart_product'];
            } elseif ($operator == 'up') {
                $sql = 'SELECT stock.out_of_stock, IFNULL(stock.quantity, 0) as quantity, IFNULL(stock.quantity_remainder, 0) as quantity_remainder
						FROM ' . _DB_PREFIX_ . 'product p
						' . Product::sqlStock('p', $id_product_attribute, true, $shop) . '
						WHERE p.id_product = ' . $id_product;
                $result2 = Db::getInstance()->getRow($sql);
                // Quantity for product pack
                if (Pack::isPack($id_product)) {
                    $result2['quantity'] = Pack::getQuantity($id_product, $id_product_attribute);
                }
                $total_quantity = PP::qtyPolicyLegacy($properties['pp_qty_policy']) ? $quantity : ($ext_prop_quantities !== null && $ext_qty > 0 ? $quantity * $ext_qty : $quantity);
                if (!Product::isAvailableWhenOutOfStock((int) $result2['out_of_stock'])) {
                    if ($total_quantity > $result2['quantity'] + (PP::qtyPolicyFractional($properties['pp_qty_policy']) ? (double) $result2['quantity_remainder'] : 0)) {
                        return false;
                    }
                }
                if (PP::qtyPolicyFractional($properties['pp_qty_policy']) && $ext_prop_quantities !== null && $ext_qty > 0) {
                    if ($ext_qty < $minimal_quantity) {
                        return -1;
                    } else {
                        if ($total_quantity < $minimal_quantity) {
                            return -1;
                        }
                    }
                }
                $result_add = Db::getInstance()->insert('cart_product', array('id_product' => (int) $id_product, 'id_product_attribute' => (int) $id_product_attribute, 'id_cart' => (int) $this->id, 'id_address_delivery' => (int) $id_address_delivery, 'id_shop' => $shop->id, 'quantity' => PP::qtyPolicyLegacy($properties['pp_qty_policy']) ? $quantity : ($ext_prop_quantities !== null && $ext_qty > 0 ? $ext_qty : 1), 'quantity_fractional' => PP::qtyPolicyLegacy($properties['pp_qty_policy']) ? 0 : $quantity, 'date_add' => date('Y-m-d H:i:s')));
                if (!$result_add) {
                    return false;
                }
                $id_cart_product = Db::getInstance()->Insert_ID();
                if (count($ext_prop_quantities)) {
                    $db = Db::getInstance();
                    foreach ($ext_prop_quantities as $index => $value) {
                        $db->insert('pp_product_ext', array('id_cart_product' => (int) $id_cart_product, 'position' => (int) $index, 'quantity' => (double) $value));
                    }
                }
            }
            $this->last_icp = $id_cart_product;
        }
        // refresh cache of self::_products
        $this->_products = $this->getProducts(true);
        $this->update();
        $context = Context::getContext()->cloneContext();
        $context->cart = $this;
        Cache::clean('getContextualValue_*');
        if ($auto_add_cart_rule) {
            CartRule::autoAddToCart($context);
        }
        if ($product->customizable) {
            return $this->_updateCustomizationQuantity($quantity, (int) $id_customization, (int) $id_product, (int) $id_product_attribute, (int) $id_address_delivery, $operator, $id_cart_product);
        } else {
            return true;
        }
    }
 public function ajaxProcessSearchProducts()
 {
     Context::getContext()->customer = new Customer((int) Tools::getValue('id_customer'));
     $currency = new Currency((int) Tools::getValue('id_currency'));
     if ($products = Product::searchByName((int) $this->context->language->id, pSQL(Tools::getValue('product_search')))) {
         foreach ($products as &$product) {
             // Formatted price
             $product['formatted_price'] = Tools::displayPrice(Tools::convertPrice($product['price_tax_incl'], $currency), $currency);
             // Concret price
             $product['price_tax_incl'] = Tools::ps_round(Tools::convertPrice($product['price_tax_incl'], $currency), 2);
             $product['price_tax_excl'] = Tools::ps_round(Tools::convertPrice($product['price_tax_excl'], $currency), 2);
             $productObj = new Product((int) $product['id_product'], false, (int) $this->context->language->id);
             $combinations = array();
             $product["pproperties"] = PP::safeOutput($productObj->productProperties());
             $attributes = $productObj->getAttributesGroups((int) $this->context->language->id);
             // Tax rate for this customer
             if (Tools::isSubmit('id_address')) {
                 $product['tax_rate'] = $productObj->getTaxesRate(new Address(Tools::getValue('id_address')));
             }
             $product['warehouse_list'] = array();
             foreach ($attributes as $attribute) {
                 if (!isset($combinations[$attribute['id_product_attribute']]['attributes'])) {
                     $combinations[$attribute['id_product_attribute']]['attributes'] = '';
                 }
                 $combinations[$attribute['id_product_attribute']]['attributes'] .= $attribute['attribute_name'] . ' - ';
                 $combinations[$attribute['id_product_attribute']]['id_product_attribute'] = $attribute['id_product_attribute'];
                 $combinations[$attribute['id_product_attribute']]['default_on'] = $attribute['default_on'];
                 if (!isset($combinations[$attribute['id_product_attribute']]['price'])) {
                     $price_tax_incl = Product::getPriceStatic((int) $product['id_product'], true, $attribute['id_product_attribute']);
                     $price_tax_excl = Product::getPriceStatic((int) $product['id_product'], false, $attribute['id_product_attribute']);
                     $combinations[$attribute['id_product_attribute']]['price_tax_incl'] = Tools::ps_round(Tools::convertPrice($price_tax_incl, $currency), 2);
                     $combinations[$attribute['id_product_attribute']]['price_tax_excl'] = Tools::ps_round(Tools::convertPrice($price_tax_excl, $currency), 2);
                     $combinations[$attribute['id_product_attribute']]['formatted_price'] = Tools::displayPrice(Tools::convertPrice($price_tax_excl, $currency), $currency);
                 }
                 if (!isset($combinations[$attribute['id_product_attribute']]['qty_in_stock'])) {
                     $combinations[$attribute['id_product_attribute']]['qty_in_stock'] = StockAvailable::getQuantityAvailableByProduct((int) $product['id_product'], $attribute['id_product_attribute'], (int) $this->context->shop->id);
                 }
                 if (Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT') && (int) $product['advanced_stock_management'] == 1) {
                     $product['warehouse_list'][$attribute['id_product_attribute']] = Warehouse::getProductWarehouseList($product['id_product'], $attribute['id_product_attribute']);
                 } else {
                     $product['warehouse_list'][$attribute['id_product_attribute']] = array();
                 }
                 $product['stock'][$attribute['id_product_attribute']] = Product::getRealQuantity($product['id_product'], $attribute['id_product_attribute']);
             }
             if (Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT') && (int) $product['advanced_stock_management'] == 1) {
                 $product['warehouse_list'][0] = Warehouse::getProductWarehouseList($product['id_product']);
             } else {
                 $product['warehouse_list'][0] = array();
             }
             $product['stock'][0] = StockAvailable::getQuantityAvailableByProduct((int) $product['id_product'], 0, (int) $this->context->shop->id);
             foreach ($combinations as &$combination) {
                 $combination['attributes'] = rtrim($combination['attributes'], ' - ');
             }
             $product['combinations'] = $combinations;
             if ($product['customizable']) {
                 $product_instance = new Product((int) $product['id_product']);
                 $product['customization_fields'] = $product_instance->getCustomizationFields($this->context->language->id);
             }
         }
         $to_return = array('products' => $products, 'found' => true);
     } else {
         $to_return = array('found' => false);
     }
     $this->content = Tools::jsonEncode($to_return);
 }