public static function getPacksTable($id_product, $id_lang, $full = false, $limit = NULL) { $price_sql = Product::getProductPriceSql('p.id_product', 'pp'); $sql = "\n\t\t SELECT\n p.*, pl.*, i.`id_image`, il.`legend`, t.`rate`\n\t\t FROM\n `PREFIX_product` p\n\t\t NATURAL LEFT JOIN `PREFIX_product_lang` pl\n\t\t LEFT JOIN `PREFIX_image` i ON\n i.`id_product` = p.`id_product` AND i.`cover` = 1\n\t\t LEFT JOIN `PREFIX_image_lang` il ON\n i.`id_image` = il.`id_image` AND il.`id_lang` = {$id_lang}\n {$price_sql}\n\t\t LEFT JOIN `PREFIX_tax` t ON\n t.`id_tax` = pp.`id_tax`\n\t\t WHERE pl.`id_lang` = {$id_lang}\n\t\t AND p.`id_product` IN (\n\t\t\t SELECT a.`id_product_pack`\n\t\t\t FROM `PREFIX_pack` a\n\t\t\t WHERE a.`id_product_item` = {$id_product})\n\t\t"; $sql = str_replace('PREFIX_', _DB_PREFIX_, $sql); $result = Db::getInstance()->ExecuteS($sql); if ($limit) { $sql .= ' LIMIT ' . intval($limit); } $result = Db::getInstance()->ExecuteS($sql); if (!$full) { return $result; } $arrayResult = array(); foreach ($result as $row) { if (!Pack::isPacked($row['id_product'])) { $arrayResult[] = Product::getProductProperties($id_lang, $row); } } return $arrayResult; }
public static function getPacksTable($id_product, $id_lang, $full = false, $limit = null) { if (!Pack::isFeatureActive()) { return array(); } $packs = Db::getInstance()->getValue(' SELECT GROUP_CONCAT(a.`id_product_pack`) FROM `' . _DB_PREFIX_ . 'pack` a WHERE a.`id_product_item` = ' . (int) $id_product); if (!(int) $packs) { return array(); } $context = Context::getContext(); $sql = ' SELECT p.*, product_shop.*, pl.*, image_shop.`id_image` id_image, il.`legend`, IFNULL(product_attribute_shop.id_product_attribute, 0) id_product_attribute FROM `' . _DB_PREFIX_ . 'product` p NATURAL LEFT JOIN `' . _DB_PREFIX_ . 'product_lang` pl ' . Shop::addSqlAssociation('product', 'p') . ' LEFT JOIN `' . _DB_PREFIX_ . 'product_attribute_shop` product_attribute_shop ON (p.`id_product` = product_attribute_shop.`id_product` AND product_attribute_shop.`default_on` = 1 AND product_attribute_shop.id_shop=' . (int) $context->shop->id . ') LEFT JOIN `' . _DB_PREFIX_ . 'image_shop` image_shop ON (image_shop.`id_product` = p.`id_product` AND image_shop.cover=1 AND image_shop.id_shop=' . (int) $context->shop->id . ') LEFT JOIN `' . _DB_PREFIX_ . 'image_lang` il ON (image_shop.`id_image` = il.`id_image` AND il.`id_lang` = ' . (int) $id_lang . ') WHERE pl.`id_lang` = ' . (int) $id_lang . ' ' . Shop::addSqlRestrictionOnLang('pl') . ' AND p.`id_product` IN (' . $packs . ') GROUP BY p.id_product'; if ($limit) { $sql .= ' LIMIT ' . (int) $limit; } $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql); if (!$full) { return $result; } $array_result = array(); foreach ($result as $row) { if (!Pack::isPacked($row['id_product'])) { $array_result[] = Product::getProductProperties($id_lang, $row); } } return $array_result; }
public static function getPacksTable($id_product, $id_lang, $full = false, $limit = null) { if (!Pack::isFeatureActive()) { return array(); } $packs = Db::getInstance()->getValue(' SELECT GROUP_CONCAT(a.`id_product_pack`) FROM `' . _DB_PREFIX_ . 'pack` a WHERE a.`id_product_item` = ' . (int) $id_product); if (!(int) $packs) { return array(); } $sql = ' SELECT p.*, product_shop.*, pl.*, image_shop.`id_image`, il.`legend` FROM `' . _DB_PREFIX_ . 'product` p NATURAL LEFT JOIN `' . _DB_PREFIX_ . 'product_lang` pl ' . Shop::addSqlAssociation('product', 'p') . ' LEFT JOIN `' . _DB_PREFIX_ . 'image` i ON (i.`id_product` = p.`id_product`)' . Shop::addSqlAssociation('image', 'i', false, 'image_shop.cover=1') . ' LEFT JOIN `' . _DB_PREFIX_ . 'image_lang` il ON (i.`id_image` = il.`id_image` AND il.`id_lang` = ' . (int) $id_lang . ') WHERE pl.`id_lang` = ' . (int) $id_lang . ' ' . Shop::addSqlRestrictionOnLang('pl') . ' AND p.`id_product` IN (' . $packs . ') AND ((image_shop.id_image IS NOT NULL OR i.id_image IS NULL) OR (image_shop.id_image IS NULL AND i.cover=1))'; if ($limit) { $sql .= ' LIMIT ' . (int) $limit; } $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql); if (!$full) { return $result; } $array_result = array(); foreach ($result as $row) { if (!Pack::isPacked($row['id_product'])) { $array_result[] = Product::getProductProperties($id_lang, $row); } } return $array_result; }
/** * Is this product in a pack? * If $id_product_attribute specified, then will restrict search on the given combination, * else this method will match a product if at least one of all its combination is in a pack. * * @param Product $product * @param integer $id_product_attribute Optional combination of the product * @return boolean */ public function isPacked($product, $id_product_attribute = false) { return Pack::isPacked($product->id, $id_product_attribute); }
public function initFormInformations($product) { if (!$this->default_form_language) { $this->getLanguages(); } $data = $this->createTemplate($this->tpl_form); $currency = $this->context->currency; $data->assign('languages', $this->_languages); $data->assign('default_form_language', $this->default_form_language); $data->assign('currency', $currency); $this->object = $product; //$this->display = 'edit'; $data->assign('product_name_redirected', Product::getProductName((int) $product->id_product_redirected, null, (int) $this->context->language->id)); /* * Form for adding a virtual product like software, mp3, etc... */ $product_download = new ProductDownload(); if ($id_product_download = $product_download->getIdFromIdProduct($this->getFieldValue($product, 'id'))) { $product_download = new ProductDownload($id_product_download); } $product->{'productDownload'} = $product_download; $cache_default_attribute = (int) $this->getFieldValue($product, 'cache_default_attribute'); $product_props = array(); // global informations array_push($product_props, 'reference', 'ean13', 'upc', 'available_for_order', 'show_price', 'online_only', 'id_manufacturer'); // specific / detailled information array_push($product_props, 'width', 'height', 'weight', 'active', 'is_virtual', 'cache_default_attribute', 'uploadable_files', 'text_fields'); // prices array_push($product_props, 'price', 'wholesale_price', 'id_tax_rules_group', 'unit_price_ratio', 'on_sale', 'unity', 'minimum_quantity', 'additional_shipping_cost', 'available_now', 'available_later', 'available_date'); if (Configuration::get('PS_USE_ECOTAX')) { array_push($product_props, 'ecotax'); } foreach ($product_props as $prop) { $product->{$prop} = $this->getFieldValue($product, $prop); } $product->name['class'] = 'updateCurrentText'; if (!$product->id || Configuration::get('PS_FORCE_FRIENDLY_PRODUCT')) { $product->name['class'] .= ' copy2friendlyUrl'; } $images = Image::getImages($this->context->language->id, $product->id); if (is_array($images)) { foreach ($images as $k => $image) { $images[$k]['src'] = $this->context->link->getImageLink($product->link_rewrite[$this->context->language->id], $product->id . '-' . $image['id_image'], 'small_default'); } $data->assign('images', $images); } $data->assign('imagesTypes', ImageType::getImagesTypes('products')); $product->tags = Tag::getProductTags($product->id); $data->assign('product_type', (int) Tools::getValue('type_product', $product->getType())); $data->assign('is_in_pack', (int) Pack::isPacked($product->id)); $check_product_association_ajax = false; if (Shop::isFeatureActive() && Shop::getContext() != Shop::CONTEXT_ALL) { $check_product_association_ajax = true; } // TinyMCE $iso_tiny_mce = $this->context->language->iso_code; $iso_tiny_mce = file_exists(_PS_ROOT_DIR_ . '/js/tiny_mce/langs/' . $iso_tiny_mce . '.js') ? $iso_tiny_mce : 'en'; $data->assign('ad', dirname($_SERVER['PHP_SELF'])); $data->assign('iso_tiny_mce', $iso_tiny_mce); $data->assign('check_product_association_ajax', $check_product_association_ajax); $data->assign('id_lang', $this->context->language->id); $data->assign('product', $product); $data->assign('token', $this->token); $data->assign('currency', $currency); $data->assign($this->tpl_form_vars); $data->assign('link', $this->context->link); $data->assign('PS_PRODUCT_SHORT_DESC_LIMIT', Configuration::get('PS_PRODUCT_SHORT_DESC_LIMIT') ? Configuration::get('PS_PRODUCT_SHORT_DESC_LIMIT') : 400); $this->tpl_form_vars['product'] = $product; $this->tpl_form_vars['custom_form'] = $data->fetch(); }
public static function getPacksTable($id_product, $id_lang, $full = false, $limit = NULL) { $packs = Db::getInstance()->getValue(' SELECT GROUP_CONCAT(a.`id_product_pack`) FROM `' . _DB_PREFIX_ . 'pack` a WHERE a.`id_product_item` = ' . (int) $id_product); if (!(int) $packs) { return array(); } $sql = ' SELECT p.*, pl.*, i.`id_image`, il.`legend`, t.`rate` FROM `' . _DB_PREFIX_ . 'product` p NATURAL LEFT JOIN `' . _DB_PREFIX_ . 'product_lang` pl LEFT JOIN `' . _DB_PREFIX_ . 'image` i ON (i.`id_product` = p.`id_product` AND i.`cover` = 1) LEFT JOIN `' . _DB_PREFIX_ . 'image_lang` il ON (i.`id_image` = il.`id_image` AND il.`id_lang` = ' . (int) $id_lang . ') LEFT JOIN `' . _DB_PREFIX_ . 'tax_rule` tr ON (p.`id_tax_rules_group` = tr.`id_tax_rules_group` AND tr.`id_country` = ' . (int) Country::getDefaultCountryId() . ' AND tr.`id_state` = 0) LEFT JOIN `' . _DB_PREFIX_ . 'tax` t ON (t.`id_tax` = tr.`id_tax`) LEFT JOIN `' . _DB_PREFIX_ . 'tax_lang` tl ON (t.`id_tax` = tl.`id_tax` AND tl.`id_lang` = ' . (int) $id_lang . ') WHERE pl.`id_lang` = ' . (int) $id_lang . ' AND p.`id_product` IN (' . $packs . ')'; if ($limit) { $sql .= ' LIMIT ' . (int) $limit; } $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS($sql); if (!$full) { return $result; } $arrayResult = array(); foreach ($result as $row) { if (!Pack::isPacked($row['id_product'])) { $arrayResult[] = Product::getProductProperties($id_lang, $row); } } return $arrayResult; }
public static function getPacksTable($id_product, $id_lang, $full = false, $limit = NULL) { $sql = ' SELECT p.*, pl.*, i.`id_image`, il.`legend`, t.`rate` FROM `' . _DB_PREFIX_ . 'product` p NATURAL LEFT JOIN `' . _DB_PREFIX_ . 'product_lang` pl LEFT JOIN `' . _DB_PREFIX_ . 'image` i ON (i.`id_product` = p.`id_product` AND i.`cover` = 1) LEFT JOIN `' . _DB_PREFIX_ . 'image_lang` il ON (i.`id_image` = il.`id_image` AND il.`id_lang` = ' . intval($id_lang) . ') LEFT JOIN `' . _DB_PREFIX_ . 'tax` t ON (t.`id_tax` = p.`id_tax`) WHERE pl.`id_lang` = ' . intval($id_lang) . ' AND p.`id_product` IN ( SELECT a.`id_product_pack` FROM `' . _DB_PREFIX_ . 'pack` a WHERE a.`id_product_item` = ' . intval($id_product) . ') '; if ($limit) { $sql .= ' LIMIT ' . intval($limit); } $result = Db::getInstance()->ExecuteS($sql); if (!$full) { return $result; } $arrayResult = array(); foreach ($result as $row) { if (!Pack::isPacked($row['id_product'])) { $arrayResult[] = Product::getProductProperties($id_lang, $row); } } return $arrayResult; }
/** * @see StockManagerInterface::removeProduct() * * @param int $id_product * @param int|null $id_product_attribute * @param Warehouse $warehouse * @param int $quantity * @param int $id_stock_mvt_reason * @param bool $is_usable * @param int|null $id_order * @param int $ignore_pack * @param Employee|null $employee * * @return array * @throws PrestaShopException */ public function removeProduct($id_product, $id_product_attribute = null, Warehouse $warehouse, $quantity, $id_stock_mvt_reason, $is_usable = true, $id_order = null, $ignore_pack = 0, $employee = null) { $return = array(); if (!Validate::isLoadedObject($warehouse) || !$quantity || !$id_product) { return $return; } if (!StockMvtReason::exists($id_stock_mvt_reason)) { $id_stock_mvt_reason = Configuration::get('PS_STOCK_MVT_DEC_REASON_DEFAULT'); } $context = Context::getContext(); // Special case of a pack if (Pack::isPack((int) $id_product) && !$ignore_pack) { if (Validate::isLoadedObject($product = new Product((int) $id_product))) { // Gets items if ($product->pack_stock_type == 1 || $product->pack_stock_type == 2 || $product->pack_stock_type == 3 && Configuration::get('PS_PACK_STOCK_TYPE') > 0) { $products_pack = Pack::getItems((int) $id_product, (int) Configuration::get('PS_LANG_DEFAULT')); // Foreach item foreach ($products_pack as $product_pack) { if ($product_pack->advanced_stock_management == 1) { $product_warehouses = Warehouse::getProductWarehouseList($product_pack->id, $product_pack->id_pack_product_attribute); $warehouse_stock_found = false; foreach ($product_warehouses as $product_warehouse) { if (!$warehouse_stock_found) { if (Warehouse::exists($product_warehouse['id_warehouse'])) { $current_warehouse = new Warehouse($product_warehouse['id_warehouse']); $return[] = $this->removeProduct($product_pack->id, $product_pack->id_pack_product_attribute, $current_warehouse, $product_pack->pack_quantity * $quantity, $id_stock_mvt_reason, $is_usable, $id_order); // The product was found on this warehouse. Stop the stock searching. $warehouse_stock_found = !empty($return[count($return) - 1]); } } } } } } if ($product->pack_stock_type == 0 || $product->pack_stock_type == 2 || $product->pack_stock_type == 3 && (Configuration::get('PS_PACK_STOCK_TYPE') == 0 || Configuration::get('PS_PACK_STOCK_TYPE') == 2)) { $return = array_merge($return, $this->removeProduct($id_product, $id_product_attribute, $warehouse, $quantity, $id_stock_mvt_reason, $is_usable, $id_order, 1)); } } else { return false; } } else { // gets total quantities in stock for the current product $physical_quantity_in_stock = (int) $this->getProductPhysicalQuantities($id_product, $id_product_attribute, array($warehouse->id), false); $usable_quantity_in_stock = (int) $this->getProductPhysicalQuantities($id_product, $id_product_attribute, array($warehouse->id), true); // check quantity if we want to decrement unusable quantity if (!$is_usable) { $quantity_in_stock = $physical_quantity_in_stock - $usable_quantity_in_stock; } else { $quantity_in_stock = $usable_quantity_in_stock; } // checks if it's possible to remove the given quantity if ($quantity_in_stock < $quantity) { return $return; } $stock_collection = $this->getStockCollection($id_product, $id_product_attribute, $warehouse->id); $stock_collection->getAll(); // check if the collection is loaded if (count($stock_collection) <= 0) { return $return; } $stock_history_qty_available = array(); $mvt_params = array(); $stock_params = array(); $quantity_to_decrement_by_stock = array(); $global_quantity_to_decrement = $quantity; // switch on MANAGEMENT_TYPE switch ($warehouse->management_type) { // case CUMP mode case 'WA': /** @var Stock $stock */ // There is one and only one stock for a given product in a warehouse in this mode $stock = $stock_collection->current(); $mvt_params = array('id_stock' => $stock->id, 'physical_quantity' => $quantity, 'id_stock_mvt_reason' => $id_stock_mvt_reason, 'id_order' => $id_order, 'price_te' => $stock->price_te, 'last_wa' => $stock->price_te, 'current_wa' => $stock->price_te, 'id_employee' => (int) $context->employee->id ? (int) $context->employee->id : $employee->id, 'employee_firstname' => $context->employee->firstname ? $context->employee->firstname : $employee->firstname, 'employee_lastname' => $context->employee->lastname ? $context->employee->lastname : $employee->lastname, 'sign' => -1); $stock_params = array('physical_quantity' => $stock->physical_quantity - $quantity, 'usable_quantity' => $is_usable ? $stock->usable_quantity - $quantity : $stock->usable_quantity); // saves stock in warehouse $stock->hydrate($stock_params); $stock->update(); // saves stock mvt $stock_mvt = new StockMvt(); $stock_mvt->hydrate($mvt_params); $stock_mvt->save(); $return[$stock->id]['quantity'] = $quantity; $return[$stock->id]['price_te'] = $stock->price_te; break; case 'LIFO': case 'FIFO': // for each stock, parse its mvts history to calculate the quantities left for each positive mvt, // according to the instant available quantities for this stock foreach ($stock_collection as $stock) { /** @var Stock $stock */ $left_quantity_to_check = $stock->physical_quantity; if ($left_quantity_to_check <= 0) { continue; } $resource = Db::getInstance(_PS_USE_SQL_SLAVE_)->query(' SELECT sm.`id_stock_mvt`, sm.`date_add`, sm.`physical_quantity`, IF ((sm2.`physical_quantity` is null), sm.`physical_quantity`, (sm.`physical_quantity` - SUM(sm2.`physical_quantity`))) as qty FROM `' . _DB_PREFIX_ . 'stock_mvt` sm LEFT JOIN `' . _DB_PREFIX_ . 'stock_mvt` sm2 ON sm2.`referer` = sm.`id_stock_mvt` WHERE sm.`sign` = 1 AND sm.`id_stock` = ' . (int) $stock->id . ' GROUP BY sm.`id_stock_mvt` ORDER BY sm.`date_add` DESC'); while ($row = Db::getInstance()->nextRow($resource)) { // break - in FIFO mode, we have to retreive the oldest positive mvts for which there are left quantities if ($warehouse->management_type == 'FIFO') { if ($row['qty'] == 0) { break; } } // converts date to timestamp $date = new DateTime($row['date_add']); $timestamp = $date->format('U'); // history of the mvt $stock_history_qty_available[$timestamp] = array('id_stock' => $stock->id, 'id_stock_mvt' => (int) $row['id_stock_mvt'], 'qty' => (int) $row['qty']); // break - in LIFO mode, checks only the necessary history to handle the global quantity for the current stock if ($warehouse->management_type == 'LIFO') { $left_quantity_to_check -= (int) $row['qty']; if ($left_quantity_to_check <= 0) { break; } } } } if ($warehouse->management_type == 'LIFO') { // orders stock history by timestamp to get newest history first krsort($stock_history_qty_available); } else { // orders stock history by timestamp to get oldest history first ksort($stock_history_qty_available); } // checks each stock to manage the real quantity to decrement for each of them foreach ($stock_history_qty_available as $entry) { if ($entry['qty'] >= $global_quantity_to_decrement) { $quantity_to_decrement_by_stock[$entry['id_stock']][$entry['id_stock_mvt']] = $global_quantity_to_decrement; $global_quantity_to_decrement = 0; } else { $quantity_to_decrement_by_stock[$entry['id_stock']][$entry['id_stock_mvt']] = $entry['qty']; $global_quantity_to_decrement -= $entry['qty']; } if ($global_quantity_to_decrement <= 0) { break; } } // for each stock, decrements it and logs the mvts foreach ($stock_collection as $stock) { if (array_key_exists($stock->id, $quantity_to_decrement_by_stock) && is_array($quantity_to_decrement_by_stock[$stock->id])) { $total_quantity_for_current_stock = 0; foreach ($quantity_to_decrement_by_stock[$stock->id] as $id_mvt_referrer => $qte) { $mvt_params = array('id_stock' => $stock->id, 'physical_quantity' => $qte, 'id_stock_mvt_reason' => $id_stock_mvt_reason, 'id_order' => $id_order, 'price_te' => $stock->price_te, 'sign' => -1, 'referer' => $id_mvt_referrer, 'id_employee' => (int) $context->employee->id ? (int) $context->employee->id : $employee->id); // saves stock mvt $stock_mvt = new StockMvt(); $stock_mvt->hydrate($mvt_params); $stock_mvt->save(); $total_quantity_for_current_stock += $qte; } $stock_params = array('physical_quantity' => $stock->physical_quantity - $total_quantity_for_current_stock, 'usable_quantity' => $is_usable ? $stock->usable_quantity - $total_quantity_for_current_stock : $stock->usable_quantity); $return[$stock->id]['quantity'] = $total_quantity_for_current_stock; $return[$stock->id]['price_te'] = $stock->price_te; // saves stock in warehouse $stock->hydrate($stock_params); $stock->update(); } } break; } if (Pack::isPacked($id_product, $id_product_attribute)) { $packs = Pack::getPacksContainingItem($id_product, $id_product_attribute, (int) Configuration::get('PS_LANG_DEFAULT')); foreach ($packs as $pack) { // Decrease stocks of the pack only if pack is in linked stock mode (option called 'Decrement both') if (!((int) $pack->pack_stock_type == 2) && !((int) $pack->pack_stock_type == 3 && (int) Configuration::get('PS_PACK_STOCK_TYPE') == 2)) { continue; } // Decrease stocks of the pack only if there is not enough items to constituate the actual pack stocks. // How many packs can be constituated with the remaining product stocks $quantity_by_pack = $pack->pack_item_quantity; $stock_available_quantity = $quantity_in_stock - $quantity; $max_pack_quantity = max(array(0, floor($stock_available_quantity / $quantity_by_pack))); $quantity_delta = Pack::getQuantity($pack->id) - $max_pack_quantity; if ($pack->advanced_stock_management == 1 && $quantity_delta > 0) { $product_warehouses = Warehouse::getPackWarehouses($pack->id); $warehouse_stock_found = false; foreach ($product_warehouses as $product_warehouse) { if (!$warehouse_stock_found) { if (Warehouse::exists($product_warehouse)) { $current_warehouse = new Warehouse($product_warehouse); $return[] = $this->removeProduct($pack->id, null, $current_warehouse, $quantity_delta, $id_stock_mvt_reason, $is_usable, $id_order, 1); // The product was found on this warehouse. Stop the stock searching. $warehouse_stock_found = !empty($return[count($return) - 1]); } } } } } } } // if we remove a usable quantity, exec hook if ($is_usable) { Hook::exec('actionProductCoverage', array('id_product' => $id_product, 'id_product_attribute' => $id_product_attribute, 'warehouse' => $warehouse)); } return $return; }