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(); $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); }
/** * For a given pack, returns the warehouse it can be shipped from * * @param int $id_product * @return int|bool id_warehouse or false */ public static function getPackWarehouses($id_product, $id_shop = null) { if (!Pack::isPack($id_product)) { return false; } if (is_null($id_shop)) { $id_shop = Context::getContext()->shop->id; } // warehouses of the pack $pack_warehouses = WarehouseProductLocation::getCollection((int) $id_product); // products in the pack $products = Pack::getItems((int) $id_product, Configuration::get('PS_LANG_DEFAULT')); // array with all warehouses id to check $list = array(); // fills $list foreach ($pack_warehouses as $pack_warehouse) { $list['pack_warehouses'][] = (int) $pack_warehouse->id_warehouse; } // for each products in the pack foreach ($products as $product) { if ($product->advanced_stock_management) { // gets the warehouses of one product $product_warehouses = Warehouse::getProductWarehouseList((int) $product->id, 0, (int) $id_shop); $list[(int) $product->id] = array(); // fills array with warehouses for this product foreach ($product_warehouses as $product_warehouse) { $list[(int) $product->id][] = $product_warehouse['id_warehouse']; } } } $res = false; // returns final list if (count($list) > 1) { $res = call_user_func_array('array_intersect', $list); } return $res; }
/** * Get products grouped by package and by addresses to be sent individualy (one package = one shipping cost). * * @return array array( * 0 => array( // First address * 0 => array( // First package * 'product_list' => array(...), * 'carrier_list' => array(...), * 'id_warehouse' => array(...), * ), * ), * ); * @todo Add avaibility check */ public function getPackageList($flush = false) { static $cache = array(); if (isset($cache[(int) $this->id . '_' . (int) $this->id_address_delivery]) && $cache[(int) $this->id . '_' . (int) $this->id_address_delivery] !== false && !$flush) { return $cache[(int) $this->id . '_' . (int) $this->id_address_delivery]; } $product_list = $this->getProducts(); // Step 1 : Get product informations (warehouse_list and carrier_list), count warehouse // Determine the best warehouse to determine the packages // For that we count the number of time we can use a warehouse for a specific delivery address $warehouse_count_by_address = array(); $warehouse_carrier_list = array(); $stock_management_active = Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT'); foreach ($product_list as &$product) { if ((int) $product['id_address_delivery'] == 0) { $product['id_address_delivery'] = (int) $this->id_address_delivery; } if (!isset($warehouse_count_by_address[$product['id_address_delivery']])) { $warehouse_count_by_address[$product['id_address_delivery']] = array(); } $product['warehouse_list'] = array(); if ($stock_management_active && ((int) $product['advanced_stock_management'] == 1 || Pack::usesAdvancedStockManagement((int) $product['id_product']))) { $warehouse_list = Warehouse::getProductWarehouseList($product['id_product'], $product['id_product_attribute'], $this->id_shop); if (count($warehouse_list) == 0) { $warehouse_list = Warehouse::getProductWarehouseList($product['id_product'], $product['id_product_attribute']); } // Does the product is in stock ? // If yes, get only warehouse where the product is in stock $warehouse_in_stock = array(); $manager = StockManagerFactory::getManager(); foreach ($warehouse_list as $key => $warehouse) { $product_real_quantities = $manager->getProductRealQuantities($product['id_product'], $product['id_product_attribute'], array($warehouse['id_warehouse']), true); if ($product_real_quantities > 0 || Pack::isPack((int) $product['id_product'])) { $warehouse_in_stock[] = $warehouse; } } if (!empty($warehouse_in_stock)) { $warehouse_list = $warehouse_in_stock; $product['in_stock'] = true; } else { $product['in_stock'] = false; } } else { //simulate default warehouse $warehouse_list = array(0); $product['in_stock'] = StockAvailable::getQuantityAvailableByProduct($product['id_product'], $product['id_product_attribute']) > 0; } foreach ($warehouse_list as $warehouse) { if (!isset($warehouse_carrier_list[$warehouse['id_warehouse']])) { $warehouse_object = new Warehouse($warehouse['id_warehouse']); $warehouse_carrier_list[$warehouse['id_warehouse']] = $warehouse_object->getCarriers(); } $product['warehouse_list'][] = $warehouse['id_warehouse']; if (!isset($warehouse_count_by_address[$product['id_address_delivery']][$warehouse['id_warehouse']])) { $warehouse_count_by_address[$product['id_address_delivery']][$warehouse['id_warehouse']] = 0; } $warehouse_count_by_address[$product['id_address_delivery']][$warehouse['id_warehouse']]++; } } unset($product); arsort($warehouse_count_by_address); // Step 2 : Group product by warehouse $grouped_by_warehouse = array(); foreach ($product_list as &$product) { if (!isset($grouped_by_warehouse[$product['id_address_delivery']])) { $grouped_by_warehouse[$product['id_address_delivery']] = array('in_stock' => array(), 'out_of_stock' => array()); } $product['carrier_list'] = array(); $id_warehouse = 0; foreach ($warehouse_count_by_address[$product['id_address_delivery']] as $id_war => $val) { if (in_array((int) $id_war, $product['warehouse_list'])) { $product['carrier_list'] = array_merge($product['carrier_list'], Carrier::getAvailableCarrierList(new Product($product['id_product']), $id_war, $product['id_address_delivery'], null, $this)); if (!$id_warehouse) { $id_warehouse = (int) $id_war; } } } if (!isset($grouped_by_warehouse[$product['id_address_delivery']]['in_stock'][$id_warehouse])) { $grouped_by_warehouse[$product['id_address_delivery']]['in_stock'][$id_warehouse] = array(); $grouped_by_warehouse[$product['id_address_delivery']]['out_of_stock'][$id_warehouse] = array(); } if (!$this->allow_seperated_package) { $key = 'in_stock'; } else { $key = $product['in_stock'] ? 'in_stock' : 'out_of_stock'; } if (empty($product['carrier_list'])) { $product['carrier_list'] = array(0); } $grouped_by_warehouse[$product['id_address_delivery']][$key][$id_warehouse][] = $product; } unset($product); // Step 3 : grouped product from grouped_by_warehouse by available carriers $grouped_by_carriers = array(); foreach ($grouped_by_warehouse as $id_address_delivery => $products_in_stock_list) { if (!isset($grouped_by_carriers[$id_address_delivery])) { $grouped_by_carriers[$id_address_delivery] = array('in_stock' => array(), 'out_of_stock' => array()); } foreach ($products_in_stock_list as $key => $warehouse_list) { if (!isset($grouped_by_carriers[$id_address_delivery][$key])) { $grouped_by_carriers[$id_address_delivery][$key] = array(); } foreach ($warehouse_list as $id_warehouse => $product_list) { if (!isset($grouped_by_carriers[$id_address_delivery][$key][$id_warehouse])) { $grouped_by_carriers[$id_address_delivery][$key][$id_warehouse] = array(); } foreach ($product_list as $product) { $package_carriers_key = implode(',', $product['carrier_list']); if (!isset($grouped_by_carriers[$id_address_delivery][$key][$id_warehouse][$package_carriers_key])) { $grouped_by_carriers[$id_address_delivery][$key][$id_warehouse][$package_carriers_key] = array('product_list' => array(), 'carrier_list' => $product['carrier_list'], 'warehouse_list' => $product['warehouse_list']); } $grouped_by_carriers[$id_address_delivery][$key][$id_warehouse][$package_carriers_key]['product_list'][] = $product; } } } } $package_list = array(); // Step 4 : merge product from grouped_by_carriers into $package to minimize the number of package foreach ($grouped_by_carriers as $id_address_delivery => $products_in_stock_list) { if (!isset($package_list[$id_address_delivery])) { $package_list[$id_address_delivery] = array('in_stock' => array(), 'out_of_stock' => array()); } foreach ($products_in_stock_list as $key => $warehouse_list) { if (!isset($package_list[$id_address_delivery][$key])) { $package_list[$id_address_delivery][$key] = array(); } // Count occurance of each carriers to minimize the number of packages $carrier_count = array(); foreach ($warehouse_list as $id_warehouse => $products_grouped_by_carriers) { foreach ($products_grouped_by_carriers as $data) { foreach ($data['carrier_list'] as $id_carrier) { if (!isset($carrier_count[$id_carrier])) { $carrier_count[$id_carrier] = 0; } $carrier_count[$id_carrier]++; } } } arsort($carrier_count); foreach ($warehouse_list as $id_warehouse => $products_grouped_by_carriers) { if (!isset($package_list[$id_address_delivery][$key][$id_warehouse])) { $package_list[$id_address_delivery][$key][$id_warehouse] = array(); } foreach ($products_grouped_by_carriers as $data) { foreach ($carrier_count as $id_carrier => $rate) { if (in_array($id_carrier, $data['carrier_list'])) { if (!isset($package_list[$id_address_delivery][$key][$id_warehouse][$id_carrier])) { $package_list[$id_address_delivery][$key][$id_warehouse][$id_carrier] = array('carrier_list' => $data['carrier_list'], 'warehouse_list' => $data['warehouse_list'], 'product_list' => array()); } $package_list[$id_address_delivery][$key][$id_warehouse][$id_carrier]['carrier_list'] = array_intersect($package_list[$id_address_delivery][$key][$id_warehouse][$id_carrier]['carrier_list'], $data['carrier_list']); $package_list[$id_address_delivery][$key][$id_warehouse][$id_carrier]['product_list'] = array_merge($package_list[$id_address_delivery][$key][$id_warehouse][$id_carrier]['product_list'], $data['product_list']); break; } } } } } } // Step 5 : Reduce depth of $package_list $final_package_list = array(); foreach ($package_list as $id_address_delivery => $products_in_stock_list) { if (!isset($final_package_list[$id_address_delivery])) { $final_package_list[$id_address_delivery] = array(); } foreach ($products_in_stock_list as $key => $warehouse_list) { foreach ($warehouse_list as $id_warehouse => $products_grouped_by_carriers) { foreach ($products_grouped_by_carriers as $data) { $final_package_list[$id_address_delivery][] = array('product_list' => $data['product_list'], 'carrier_list' => $data['carrier_list'], 'warehouse_list' => $data['warehouse_list'], 'id_warehouse' => $id_warehouse); } } } } $cache[(int) $this->id] = $final_package_list; return $final_package_list; }
public function initFormQuantities($obj) { if (!$this->default_form_language) { $this->getLanguages(); } $data = $this->createTemplate($this->tpl_form); $data->assign('default_form_language', $this->default_form_language); if ($obj->id) { if ($this->product_exists_in_shop) { // Get all id_product_attribute $attributes = $obj->getAttributesResume($this->context->language->id); if (empty($attributes)) { $attributes[] = array('id_product_attribute' => 0, 'attribute_designation' => ''); } // Get available quantities $available_quantity = array(); $product_designation = array(); foreach ($attributes as $attribute) { // Get available quantity for the current product attribute in the current shop $available_quantity[$attribute['id_product_attribute']] = StockAvailable::getQuantityAvailableByProduct((int) $obj->id, $attribute['id_product_attribute']); // Get all product designation $product_designation[$attribute['id_product_attribute']] = rtrim($obj->name[$this->context->language->id] . ' - ' . $attribute['attribute_designation'], ' - '); } $show_quantities = true; $shop_context = Shop::getContext(); $shop_group = new ShopGroup((int) Shop::getContextShopGroupID()); // if we are in all shops context, it's not possible to manage quantities at this level if (Shop::isFeatureActive() && $shop_context == Shop::CONTEXT_ALL) { $show_quantities = false; } elseif (Shop::isFeatureActive() && $shop_context == Shop::CONTEXT_GROUP) { // if quantities are not shared between shops of the group, it's not possible to manage them at group level if (!$shop_group->share_stock) { $show_quantities = false; } } else { // if quantities are shared between shops of the group, it's not possible to manage them for a given shop if ($shop_group->share_stock) { $show_quantities = false; } } $data->assign('ps_stock_management', Configuration::get('PS_STOCK_MANAGEMENT')); $data->assign('has_attribute', $obj->hasAttributes()); // Check if product has combination, to display the available date only for the product or for each combination if (Combination::isFeatureActive()) { $data->assign('countAttributes', (int) Db::getInstance()->getValue('SELECT COUNT(id_product) FROM ' . _DB_PREFIX_ . 'product_attribute WHERE id_product = ' . (int) $obj->id)); } else { $data->assign('countAttributes', false); } // if advanced stock management is active, checks associations $advanced_stock_management_warning = false; if (Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT') && $obj->advanced_stock_management) { $p_attributes = Product::getProductAttributesIds($obj->id); $warehouses = array(); if (!$p_attributes) { $warehouses[] = Warehouse::getProductWarehouseList($obj->id, 0); } foreach ($p_attributes as $p_attribute) { $ws = Warehouse::getProductWarehouseList($obj->id, $p_attribute['id_product_attribute']); if ($ws) { $warehouses[] = $ws; } } $warehouses = Tools::arrayUnique($warehouses); if (empty($warehouses)) { $advanced_stock_management_warning = true; } } if ($advanced_stock_management_warning) { $this->displayWarning($this->l('If you wish to use the advanced stock management, you must:')); $this->displayWarning('- ' . $this->l('associate your products with warehouses.')); $this->displayWarning('- ' . $this->l('associate your warehouses with carriers.')); $this->displayWarning('- ' . $this->l('associate your warehouses with the appropriate shops.')); } $pack_quantity = null; // if product is a pack if (Pack::isPack($obj->id)) { $items = Pack::getItems((int) $obj->id, Configuration::get('PS_LANG_DEFAULT')); // gets an array of quantities (quantity for the product / quantity in pack) $pack_quantities = array(); foreach ($items as $item) { if (!$item->isAvailableWhenOutOfStock((int) $item->out_of_stock)) { $pack_id_product_attribute = Product::getDefaultAttribute($item->id, 1); $pack_quantities[] = Product::getQuantity($item->id, $pack_id_product_attribute) / ($item->pack_quantity !== 0 ? $item->pack_quantity : 1); } } // gets the minimum if (count($pack_quantities)) { $pack_quantity = $pack_quantities[0]; foreach ($pack_quantities as $value) { if ($pack_quantity > $value) { $pack_quantity = $value; } } } if (!Warehouse::getPackWarehouses((int) $obj->id)) { $this->displayWarning($this->l('You must have a common warehouse between this pack and its product.')); } } $data->assign(array('attributes' => $attributes, 'available_quantity' => $available_quantity, 'pack_quantity' => $pack_quantity, 'stock_management_active' => Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT'), 'product_designation' => $product_designation, 'product' => $obj, 'show_quantities' => $show_quantities, 'order_out_of_stock' => Configuration::get('PS_ORDER_OUT_OF_STOCK'), 'token_preferences' => Tools::getAdminTokenLite('AdminPPreferences'), 'token' => $this->token, 'languages' => $this->_languages, 'id_lang' => $this->context->language->id)); } else { $this->displayWarning($this->l('You must save the product in this shop before managing quantities.')); } } else { $this->displayWarning($this->l('You must save this product before managing quantities.')); } $this->tpl_form_vars['custom_form'] = $data->fetch(); }
public function getDeliveryOptionList(Country $default_country = null, $flush = false) { static $cache = null; if ($cache !== null && !$flush) { return $cache; } $delivery_option_list = array(); $carriers_price = array(); $carrier_collection = array(); $package_list = $this->getPackageList(); // Foreach addresses foreach ($package_list as $id_address => $packages) { // Initialize vars $delivery_option_list[$id_address] = array(); $carriers_price[$id_address] = array(); $common_carriers = null; $best_price_carriers = array(); $best_grade_carriers = array(); $carriers_instance = array(); // Get country if ($id_address) { $address = new Address($id_address); $country = new Country($address->id_country); } else { $country = $default_country; } // Foreach packages, get the carriers with best price, best position and best grade foreach ($packages as $id_package => $package) { // No carriers available if (count($package['carrier_list']) == 1 && current($package['carrier_list']) == 0) { $package['carrier_list'] = array(103, 96, 97); // $cache = array(); // return $cache; } $carriers_price[$id_address][$id_package] = array(); // Get all common carriers for each packages to the same address if (is_null($common_carriers)) { $common_carriers = $package['carrier_list']; } else { $common_carriers = array_intersect($common_carriers, $package['carrier_list']); } $best_price = null; $best_price_carrier = null; $best_grade = null; $best_grade_carrier = null; // Foreach carriers of the package, calculate his price, check if it the best price, position and grade foreach ($package['carrier_list'] as $id_carrier) { if (!isset($carriers_instance[$id_carrier])) { $carriers_instance[$id_carrier] = new Carrier($id_carrier); } $price_with_tax = $this->getPackageShippingCost($id_carrier, true, $country, $package['product_list']); $price_without_tax = $this->getPackageShippingCost($id_carrier, false, $country, $package['product_list']); if (is_null($best_price) || $price_with_tax < $best_price) { $best_price = $price_with_tax; $best_price_carrier = $id_carrier; } $carriers_price[$id_address][$id_package][$id_carrier] = array('without_tax' => $price_without_tax, 'with_tax' => $price_with_tax); $grade = $carriers_instance[$id_carrier]->grade; if (is_null($best_grade) || $grade > $best_grade) { $best_grade = $grade; $best_grade_carrier = $id_carrier; } } $best_price_carriers[$id_package] = $best_price_carrier; $best_grade_carriers[$id_package] = $best_grade_carrier; } // Reset $best_price_carrier, it's now an array $best_price_carrier = array(); $key = ''; // Get the delivery option with the lower price foreach ($best_price_carriers as $id_package => $id_carrier) { $key .= $id_carrier . ','; if (!isset($best_price_carrier[$id_carrier])) { $best_price_carrier[$id_carrier] = array('price_with_tax' => 0, 'price_without_tax' => 0, 'package_list' => array(), 'product_list' => array()); } $best_price_carrier[$id_carrier]['price_with_tax'] += $carriers_price[$id_address][$id_package][$id_carrier]['with_tax']; $best_price_carrier[$id_carrier]['price_without_tax'] += $carriers_price[$id_address][$id_package][$id_carrier]['without_tax']; $best_price_carrier[$id_carrier]['package_list'][] = $id_package; $best_price_carrier[$id_carrier]['product_list'] = array_merge($best_price_carrier[$id_carrier]['product_list'], $packages[$id_package]['product_list']); $best_price_carrier[$id_carrier]['instance'] = $carriers_instance[$id_carrier]; } // Add the delivery option with best price as best price $delivery_option_list[$id_address][$key] = array('carrier_list' => $best_price_carrier, 'is_best_price' => true, 'is_best_grade' => false, 'unique_carrier' => count($best_price_carrier) <= 1); // Reset $best_grade_carrier, it's now an array $best_grade_carrier = array(); $key = ''; // Get the delivery option with the best grade foreach ($best_grade_carriers as $id_package => $id_carrier) { $key .= $id_carrier . ','; if (!isset($best_grade_carrier[$id_carrier])) { $best_grade_carrier[$id_carrier] = array('price_with_tax' => 0, 'price_without_tax' => 0, 'package_list' => array(), 'product_list' => array()); } $best_grade_carrier[$id_carrier]['price_with_tax'] += $carriers_price[$id_address][$id_package][$id_carrier]['with_tax']; $best_grade_carrier[$id_carrier]['price_without_tax'] += $carriers_price[$id_address][$id_package][$id_carrier]['without_tax']; $best_grade_carrier[$id_carrier]['package_list'][] = $id_package; $best_grade_carrier[$id_carrier]['product_list'] = array_merge($best_grade_carrier[$id_carrier]['product_list'], $packages[$id_package]['product_list']); $best_grade_carrier[$id_carrier]['instance'] = $carriers_instance[$id_carrier]; } // Add the delivery option with best grade as best grade if (!isset($delivery_option_list[$id_address][$key])) { $delivery_option_list[$id_address][$key] = array('carrier_list' => $best_grade_carrier, 'is_best_price' => false, 'unique_carrier' => count($best_grade_carrier) <= 1); } $delivery_option_list[$id_address][$key]['is_best_grade'] = true; // Get all delivery options with a unique carrier foreach ($common_carriers as $id_carrier) { $key = ''; $package_list = array(); $product_list = array(); $price_with_tax = 0; $price_without_tax = 0; foreach ($packages as $id_package => $package) { $key .= $id_carrier . ','; $price_with_tax += $carriers_price[$id_address][$id_package][$id_carrier]['with_tax']; $price_without_tax += $carriers_price[$id_address][$id_package][$id_carrier]['without_tax']; $package_list[] = $id_package; $product_list = array_merge($product_list, $package['product_list']); } if (!isset($delivery_option_list[$id_address][$key])) { $delivery_option_list[$id_address][$key] = array('is_best_price' => false, 'is_best_grade' => false, 'unique_carrier' => true, 'carrier_list' => array($id_carrier => array('price_with_tax' => $price_with_tax, 'price_without_tax' => $price_without_tax, 'instance' => $carriers_instance[$id_carrier], 'package_list' => $package_list, 'product_list' => $product_list))); } else { $delivery_option_list[$id_address][$key]['unique_carrier'] = count($delivery_option_list[$id_address][$key]['carrier_list']) <= 1; } } } $cart_rules = CartRule::getCustomerCartRules(Context::getContext()->cookie->id_lang, Context::getContext()->cookie->id_customer, true); $free_carriers_rules = array(); foreach ($cart_rules as $cart_rule) { if ($cart_rule['free_shipping'] && $cart_rule['carrier_restriction']) { $cr = new CartRule((int) $cart_rule['id_cart_rule']); if (Validate::isLoadedObject($cr)) { $carriers = $cr->getAssociatedRestrictions('carrier', true, false); if (is_array($carriers) && count($carriers) && isset($carriers['selected'])) { foreach ($carriers['selected'] as $carrier) { if (isset($carrier['id_carrier']) && $carrier['id_carrier']) { $free_carriers_rules[] = (int) $carrier['id_carrier']; } } } } } } $product_stock_1 = false; $product_stock_2 = false; $custom = false; $stock_management_active = Configuration::get('PS_ADVANCED_STOCK_MANAGEMENT'); if ($stock_management_active) { $products = $this->getProducts(); foreach ($products as $product) { $flag = false; $warehouse_list = Warehouse::getProductWarehouseList($product['id_product'], $product['id_product_attribute']); $manager = StockManagerFactory::getManager(); foreach ($warehouse_list as $key => $warehouse) { $product_real_quantities = $manager->getProductRealQuantities($product['id_product'], $product['id_product_attribute'], array($warehouse['id_warehouse']), true); if ($key == 0 && $product_real_quantities > 0) { $flag = true; $product_stock_1 = true; } if ($key == 1 && $product_real_quantities > 0) { $product_stock_2 = true; $flag = true; } } if (!$flag) { $custom = true; break; } } } $langs = Language::getLanguages(); // For each delivery options : // - Set the carrier list // - Calculate the price // - Calculate the average position foreach ($delivery_option_list as $id_address => $delivery_option) { foreach ($delivery_option as $key => $value) { $total_price_with_tax = 0; $total_price_without_tax = 0; $position = 0; foreach ($value['carrier_list'] as $id_carrier => $data) { $total_price_with_tax += $data['price_with_tax']; $total_price_without_tax += $data['price_without_tax']; $total_price_without_tax_with_rules = in_array($id_carrier, $free_carriers_rules) ? 0 : $total_price_without_tax; if (!isset($carrier_collection[$id_carrier])) { $carrier_collection[$id_carrier] = new Carrier($id_carrier); } switch (true) { case $custom: if ($carrier_collection[$id_carrier]->name == 'Самовывоз в Шарлотенбурге') { foreach ($langs as $lang) { $carrier_collection[$id_carrier]->delay[$lang['id_lang']] = '2-3 недели'; } } if ($carrier_collection[$id_carrier]->name == 'Самовывоз в Русском доме') { foreach ($langs as $lang) { $carrier_collection[$id_carrier]->delay[$lang['id_lang']] = '2-3 недели'; } } break; case !$custom && ($product_stock_1 && $product_stock_2): if ($carrier_collection[$id_carrier]->name == 'Самовывоз в Шарлотенбурге') { foreach ($langs as $lang) { $carrier_collection[$id_carrier]->delay[$lang['id_lang']] = '2 дня'; } } if ($carrier_collection[$id_carrier]->name == 'Самовывоз в Русском доме') { foreach ($langs as $lang) { $carrier_collection[$id_carrier]->delay[$lang['id_lang']] = '2 дня'; } } break; case !$custom && (!$product_stock_1 && $product_stock_2): if ($carrier_collection[$id_carrier]->name == 'Самовывоз в Шарлотенбурге') { foreach ($langs as $lang) { $carrier_collection[$id_carrier]->delay[$lang['id_lang']] = '2 дня'; } } if ($carrier_collection[$id_carrier]->name == 'Самовывоз в Русском доме') { foreach ($langs as $lang) { $carrier_collection[$id_carrier]->delay[$lang['id_lang']] = '1 день'; } } break; case !$custom && ($product_stock_1 && !$product_stock_2): if ($carrier_collection[$id_carrier]->name == 'Самовывоз в Шарлотенбурге') { foreach ($langs as $lang) { $carrier_collection[$id_carrier]->delay[$lang['id_lang']] = '1 день'; } } if ($carrier_collection[$id_carrier]->name == 'Самовывоз в Русском доме') { foreach ($langs as $lang) { $carrier_collection[$id_carrier]->delay[$lang['id_lang']] = '2 дня'; } } break; } $delivery_option_list[$id_address][$key]['carrier_list'][$id_carrier]['instance'] = $carrier_collection[$id_carrier]; if (file_exists(_PS_SHIP_IMG_DIR_ . $id_carrier . '.jpg')) { $delivery_option_list[$id_address][$key]['carrier_list'][$id_carrier]['logo'] = _THEME_SHIP_DIR_ . $id_carrier . '.jpg'; } else { $delivery_option_list[$id_address][$key]['carrier_list'][$id_carrier]['logo'] = false; } $position += $carrier_collection[$id_carrier]->position; } $delivery_option_list[$id_address][$key]['total_price_with_tax'] = $total_price_with_tax; $delivery_option_list[$id_address][$key]['total_price_without_tax'] = $total_price_without_tax; $delivery_option_list[$id_address][$key]['is_free'] = !$total_price_without_tax_with_rules ? true : false; $delivery_option_list[$id_address][$key]['position'] = $position / count($value['carrier_list']); } } // Sort delivery option list foreach ($delivery_option_list as &$array) { uasort($array, array('Cart', 'sortDeliveryOptionList')); } $cache = $delivery_option_list; return $delivery_option_list; }
/** * @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; }
public function initContentForQuantities() { if ($this->object->id) { $tfowlgstly = "show_quantities"; ${"GLOBALS"}["ygzeqkb"] = "show_quantities"; $gmgclvkrjy = "attributes"; ${"GLOBALS"}["jhngqfjufp"] = "attributes"; $cggvbxsk = "attributes"; ${${"GLOBALS"}["jhngqfjufp"]} = $this->object->getAttributesResume($this->context->language->id); ${"GLOBALS"}["aofqmvff"] = "attribute"; ${"GLOBALS"}["vyyogyvfbtx"] = "attributes"; $nfdcluhk = "attributes"; $khzorwi = "shop_context"; if (empty(${$nfdcluhk})) { ${$cggvbxsk}[] = array("id_product_attribute" => 0, "attribute_designation" => ""); } ${"GLOBALS"}["klqbahrije"] = "shop_context"; ${${"GLOBALS"}["ldfuknydnzr"]} = array(); ${${"GLOBALS"}["ymshseez"]} = array(); ${"GLOBALS"}["lztnksxrb"] = "group_shop"; foreach (${${"GLOBALS"}["vyyogyvfbtx"]} as ${${"GLOBALS"}["aofqmvff"]}) { $rvrxkz = "product_designation"; $ycvvjwmxtnm = "attribute"; $dxuqsu = "available_quantity"; ${$dxuqsu}[${${"GLOBALS"}["iixdipeiyldv"]}["id_product_attribute"]] = StockAvailable::getQuantityAvailableByProduct((int) $this->object->id, ${$ycvvjwmxtnm}["id_product_attribute"]); ${$rvrxkz}[${${"GLOBALS"}["iixdipeiyldv"]}["id_product_attribute"]] = rtrim($this->object->name[$this->context->language->id] . " - " . ${${"GLOBALS"}["iixdipeiyldv"]}["attribute_designation"], " - "); } ${${"GLOBALS"}["ueicxl"]} = true; ${$khzorwi} = Shop::getContext(); ${${"GLOBALS"}["lztnksxrb"]} = $this->context->shop->getGroup(); $wktpughd = "pack_quantity"; ${"GLOBALS"}["eukvwdf"] = "advanced_stock_management_warning"; if (${${"GLOBALS"}["klqbahrije"]} == Shop::CONTEXT_ALL) { ${$tfowlgstly} = false; } elseif (${${"GLOBALS"}["ohyfjtkcy"]} == Shop::CONTEXT_GROUP) { if (!$group_shop->share_stock) { ${${"GLOBALS"}["ueicxl"]} = false; } } else { $eksumjgu = "show_quantities"; if ($group_shop->share_stock) { ${$eksumjgu} = false; } } self::$smarty->assign("ps_stock_management", Configuration::get("PS_STOCK_MANAGEMENT")); self::$smarty->assign("has_attribute", $this->object->hasAttributes()); if (Combination::isFeatureActive()) { self::$smarty->assign("countAttributes", (int) Db::getInstance()->getValue("SELECT COUNT(id_product) FROM " . _DB_PREFIX_ . "product_attribute WHERE id_product = " . (int) $this->object->id)); } ${${"GLOBALS"}["eukvwdf"]} = false; if (Configuration::get("PS_ADVANCED_STOCK_MANAGEMENT") && $this->object->advanced_stock_management) { ${"GLOBALS"}["awunkp"] = "p_attributes"; ${"GLOBALS"}["qxobmbos"] = "warehouses"; ${"GLOBALS"}["cjtetqei"] = "warehouses"; $ukjfpwyojlf = "p_attribute"; ${${"GLOBALS"}["iczelyves"]} = Product::getProductAttributesIds($this->object->id); ${"GLOBALS"}["kcjlbgqb"] = "advanced_stock_management_warning"; ${"GLOBALS"}["dlsnuhn"] = "warehouses"; ${${"GLOBALS"}["qxobmbos"]} = array(); ${"GLOBALS"}["ojmjigmfve"] = "p_attributes"; if (!${${"GLOBALS"}["awunkp"]}) { ${${"GLOBALS"}["mdrvdmghqrtc"]}[] = Warehouse::getProductWarehouseList($this->object->id, 0); } foreach (${${"GLOBALS"}["ojmjigmfve"]} as ${$ukjfpwyojlf}) { ${"GLOBALS"}["uevlubu"] = "ws"; ${"GLOBALS"}["fpbyfow"] = "warehouses"; ${"GLOBALS"}["inddsyj"] = "ws"; ${${"GLOBALS"}["yrbmurnh"]} = Warehouse::getProductWarehouseList($this->object->id, ${${"GLOBALS"}["bhprusfblhn"]}["id_product_attribute"]); if (${${"GLOBALS"}["uevlubu"]}) { ${${"GLOBALS"}["fpbyfow"]}[] = ${${"GLOBALS"}["inddsyj"]}; } } ${${"GLOBALS"}["dlsnuhn"]} = array_unique(${${"GLOBALS"}["cjtetqei"]}); if (empty(${${"GLOBALS"}["mdrvdmghqrtc"]})) { ${${"GLOBALS"}["kcjlbgqb"]} = true; } } if (${${"GLOBALS"}["uucoxnutvd"]}) { $this->displayWarning($this->getMessage("If you wish to use the advanced stock management, you have to:")); $this->displayWarning("- " . $this->getMessage("associate your products with warehouses")); $this->displayWarning("- " . $this->getMessage("associate your warehouses with carriers")); $this->displayWarning("- " . $this->getMessage("associate your warehouses with the appropriate shops")); } ${${"GLOBALS"}["qbmqjuoutyh"]} = null; if (Pack::isPack($this->object->id)) { ${"GLOBALS"}["wdcmwsfvsft"] = "pack_quantity"; $mdjqucflf = "items"; ${${"GLOBALS"}["wfbswtei"]} = Pack::getItems((int) $this->object->id, Configuration::get("PS_LANG_DEFAULT")); $mhikkwxp = "pack_quantities"; ${"GLOBALS"}["kamnnzyptd"] = "pack_quantities"; ${${"GLOBALS"}["kamnnzyptd"]} = array(); foreach (${$mdjqucflf} as ${${"GLOBALS"}["gpnqjgaosuld"]}) { if (!$item->isAvailableWhenOutOfStock((int) $item->out_of_stock)) { $gkwutr = "pack_id_product_attribute"; ${${"GLOBALS"}["wkyidmmlbbc"]} = Product::getDefaultAttribute($item->id, 1); ${${"GLOBALS"}["pnfrmcr"]}[] = Product::getQuantity($item->id, ${$gkwutr}) / ($item->pack_quantity !== 0 ? $item->pack_quantity : 1); } } $oissvbm = "pack_quantities"; ${${"GLOBALS"}["wdcmwsfvsft"]} = ${$oissvbm}[0]; foreach (${$mhikkwxp} as ${${"GLOBALS"}["kzwkbwmzgtl"]}) { ${"GLOBALS"}["iwrwjuvdmi"] = "value"; if (${${"GLOBALS"}["qbmqjuoutyh"]} > ${${"GLOBALS"}["iwrwjuvdmi"]}) { ${${"GLOBALS"}["qbmqjuoutyh"]} = ${${"GLOBALS"}["kzwkbwmzgtl"]}; } } if (!Warehouse::getPackWarehouses((int) $this->object->id)) { $this->displayWarning($this->getMessage("You must have a common warehouse between this pack and its product.")); } } ${${"GLOBALS"}["lixyhrpqnh"]} = new Language($this->id_language); self::$smarty->assign("iso_code", $lang->iso_code ? $lang->iso_code : "en"); self::$smarty->assign(array("attributes" => ${$gmgclvkrjy}, "available_quantity" => ${${"GLOBALS"}["ldfuknydnzr"]}, "pack_quantity" => ${$wktpughd}, "stock_management_active" => Configuration::get("PS_ADVANCED_STOCK_MANAGEMENT"), "product_designation" => ${${"GLOBALS"}["ymshseez"]}, "show_quantities" => ${${"GLOBALS"}["ygzeqkb"]}, "order_out_of_stock" => Configuration::get("PS_ORDER_OUT_OF_STOCK"))); } else { $this->displayWarning($this->getMessage("You must save this product before managing quantities.")); } }