Example #1
0
 public function getPackageList($flush = false)
 {
     static $cache = array();
     if (isset($cache[(int) $this->cart_id . '_' . (int) $this->address_delivery_id]) && $cache[(int) $this->cart_id . '_' . (int) $this->address_delivery_id] !== false && !$flush) {
         return $cache[(int) $this->cart_id . '_' . (int) $this->address_delivery_id];
     }
     $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 = JeproshopSettingModelSetting::getValue('advanced_stock_management');
     foreach ($product_list as &$product) {
         if ((int) $product->address_delivery_id == 0) {
             $product->address_delivery_id = (int) $this->address_delivery_id;
         }
         if (!isset($warehouse_count_by_address[$product->address_delivery_id])) {
             $warehouse_count_by_address[$product->address_delivery_id] = array();
         }
         $product->warehouse_list = array();
         if ($stock_management_active && ((int) $product['advanced_stock_management'] == 1 || Pack::usesAdvancedStockManagement((int) $product->product_id))) {
             $warehouse_list = Warehouse::getProductWarehouseList($product->product_id, $product->roduct_attribute_id, $this->shop_id);
             if (count($warehouse_list) == 0) {
                 $warehouse_list = Warehouse::getProductWarehouseList($product->product_id, $product->roduct_attribute_id);
             }
             // 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->product_id, $product->product_attribute_id, array($warehouse->warehouse_id), true);
                 if ($product_real_quantities > 0 || Pack::isPack((int) $product->product_id)) {
                     $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->product_id, $product->product_attribute_id) > 0;
         }
         foreach ($warehouse_list as $warehouse) {
             if (!isset($warehouse_carrier_list[$warehouse->warehouse_id])) {
                 $warehouse_object = new JeproshopWarehouseModelWarehouse($warehouse->warehouse_id);
                 $warehouse_carrier_list[$warehouse->warehouse_id] = $warehouse_object->getCarriers();
             }
             $product->warehouse_list[] = $warehouse->warehouse_id;
             if (!isset($warehouse_count_by_address[$product->address_delivery_id][$warehouse->warehouse_id])) {
                 $warehouse_count_by_address[$product->address_delivery_id][$warehouse->warehouse_id] = 0;
             }
             $warehouse_count_by_address[$product->address_delivery_id][$warehouse->warehouse_id]++;
         }
     }
     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->address_delivery_id])) {
             $grouped_by_warehouse[$product->address_delivery_id] = array('in_stock' => array(), 'out_of_stock' => array());
         }
         $product->carrier_list = array();
         $warehouse_id = 0;
         foreach ($warehouse_count_by_address[$product->address_delivery_id] as $war_id => $val) {
             if (in_array((int) $war_id, $product->warehouse_list)) {
                 $product->carrier_list = array_merge($product->carrier_list, Carrier::getAvailableCarrierList(new Product($product->product_id), $war_id, $product->address_delivery_id, null, $this));
                 if (!$warehouse_id) {
                     $warehouse_id = (int) $war_id;
                 }
             }
         }
         if (!isset($grouped_by_warehouse[$product->address_delivery_id]['in_stock'][$warehouse_id])) {
             $grouped_by_warehouse[$product->address_delivery_id]['in_stock'][$warehouse_id] = array();
             $grouped_by_warehouse[$product->address_delivery_id]['out_of_stock'][$warehouse_id] = array();
         }
         if (!$this->allow_separated_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->address_delivery_id][$key][$warehouse_id][] = $product;
     }
     unset($product);
     // Step 3 : grouped product from grouped_by_warehouse by available carriers
     $grouped_by_carriers = array();
     foreach ($grouped_by_warehouse as $address_delivery_id => $products_in_stock_list) {
         if (!isset($grouped_by_carriers[$address_delivery_id])) {
             $grouped_by_carriers[$address_delivery_id] = array('in_stock' => array(), 'out_of_stock' => array());
         }
         foreach ($products_in_stock_list as $key => $warehouse_list) {
             if (!isset($grouped_by_carriers[$address_delivery_id][$key])) {
                 $grouped_by_carriers[$address_delivery_id][$key] = array();
             }
             foreach ($warehouse_list as $warehouse_id => $product_list) {
                 if (!isset($grouped_by_carriers[$address_delivery_id][$key][$warehouse_id])) {
                     $grouped_by_carriers[$address_delivery_id][$key][$warehouse_id] = array();
                 }
                 foreach ($product_list as $product) {
                     $package_carriers_key = implode(',', $product->carrier_list);
                     if (!isset($grouped_by_carriers[$address_delivery_id][$key][$warehouse_id][$package_carriers_key])) {
                         $grouped_by_carriers[$address_delivery_id][$key][$warehouse_id][$package_carriers_key] = array('product_list' => array(), 'carrier_list' => $product->carrier_list, 'warehouse_list' => $product->warehouse_list);
                     }
                     $grouped_by_carriers[$address_delivery_id][$key][$warehouse_id][$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 $address_delivery_id => $products_in_stock_list) {
         if (!isset($package_list[$address_delivery_id])) {
             $package_list[$address_delivery_id] = array('in_stock' => array(), 'out_of_stock' => array());
         }
         foreach ($products_in_stock_list as $key => $warehouse_list) {
             if (!isset($package_list[$address_delivery_id][$key])) {
                 $package_list[$address_delivery_id][$key] = array();
             }
             // Count occurrence of each carriers to minimize the number of packages
             $carrier_count = array();
             foreach ($warehouse_list as $warehouse_id => $products_grouped_by_carriers) {
                 foreach ($products_grouped_by_carriers as $data) {
                     foreach ($data['carrier_list'] as $carrier_id) {
                         if (!isset($carrier_count[$carrier_id])) {
                             $carrier_count[$carrier_id] = 0;
                         }
                         $carrier_count[$carrier_id]++;
                     }
                 }
             }
             arsort($carrier_count);
             foreach ($warehouse_list as $warehouse_id => $products_grouped_by_carriers) {
                 if (!isset($package_list[$address_delivery_id][$key][$warehouse_id])) {
                     $package_list[$address_delivery_id][$key][$warehouse_id] = array();
                 }
                 foreach ($products_grouped_by_carriers as $data) {
                     foreach ($carrier_count as $carrier_id => $rate) {
                         if (in_array($carrier_id, $data['carrier_list'])) {
                             if (!isset($package_list[$address_delivery_id][$key][$warehouse_id][$carrier_id])) {
                                 $package_list[$address_delivery_id][$key][$warehouse_id][$carrier_id] = array('carrier_list' => $data['carrier_list'], 'warehouse_list' => $data['warehouse_list'], 'product_list' => array());
                             }
                             $package_list[$address_delivery_id][$key][$warehouse_id][$carrier_id]['carrier_list'] = array_intersect($package_list[$address_delivery_id][$key][$warehouse_id][$carrier_id]['carrier_list'], $data['carrier_list']);
                             $package_list[$address_delivery_id][$key][$warehouse_id][$carrier_id]['product_list'] = array_merge($package_list[$address_delivery_id][$key][$warehouse_id][$carrier_id]['product_list'], $data['product_list']);
                             break;
                         }
                     }
                 }
             }
         }
     }
     // Step 5 : Reduce depth of $package_list
     $final_package_list = array();
     foreach ($package_list as $address_delivery_id => $products_in_stock_list) {
         if (!isset($final_package_list[$address_delivery_id])) {
             $final_package_list[$address_delivery_id] = array();
         }
         foreach ($products_in_stock_list as $key => $warehouse_list) {
             foreach ($warehouse_list as $warehouse_id => $products_grouped_by_carriers) {
                 foreach ($products_grouped_by_carriers as $data) {
                     $final_package_list[$address_delivery_id][] = array('product_list' => $data['product_list'], 'carrier_list' => $data['carrier_list'], 'warehouse_list' => $data['warehouse_list'], 'warehouse_id' => $warehouse_id);
                 }
             }
         }
     }
     $cache[(int) $this->cart_id] = $final_package_list;
     return $final_package_list;
 }
Example #2
0
 /**
  * For a given {product, warehouse}, gets the carrier available
  *
  * @param JeproshopProductModelProduct $product The id of the product, or an array with at least the package size and weight
  * @param int $warehouse_id
  * @param int $address_delivery_id
  * @param int $shop_id
  * @param $cart
  * @return array
  */
 public static function getAvailableCarrierList(JeproshopProductModelProduct $product, $warehouse_id, $address_delivery_id = null, $shop_id = null, $cart = null)
 {
     if (is_null($shop_id)) {
         $shop_id = JeproshopContext::getContext()->shop->shop_id;
     }
     if (is_null($cart)) {
         $cart = JeproshopContext::getContext()->cart;
     }
     $address_id = (int) (!is_null($address_delivery_id) && $address_delivery_id != 0 ? $address_delivery_id : $cart->address_delivery_id);
     if ($address_id) {
         $address = new JeproshopAddressModelAddress($address_id);
         $zone_id = JeproshopAddressModelAddress::getZoneIdByAddressId($address->address_id);
         // Check the country of the address is activated
         if (!JeproshopAddressModelAddress::isCountryActiveById($address->address_id)) {
             return array();
         }
     } else {
         $country = new JeproshopCountryModelCountry(JeproshopSettingModelSetting::getValue('default_country'));
         $izone_id = $country->zone_id;
     }
     // Does the product is linked with carriers?
     $query = new DbQuery();
     $query->select('id_carrier');
     $query->from('product_carrier', 'pc');
     $query->innerJoin('carrier', 'c', 'c.id_reference = pc.id_carrier_reference AND c.deleted = 0');
     $query->where('pc.id_product = ' . (int) $product->product_id);
     $query->where('pc.id_shop = ' . (int) $shop_id);
     $cache_id = 'Carrier::getAvailableCarrierList_' . (int) $product->id . '-' . (int) $id_shop;
     if (!Cache::isStored($cache_id)) {
         $carriers_for_product = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($query);
         Cache::store($cache_id, $carriers_for_product);
     }
     $carriers_for_product = Cache::retrieve($cache_id);
     $carrier_list = array();
     if (!empty($carriers_for_product)) {
         //the product is linked with carriers
         foreach ($carriers_for_product as $carrier) {
             //check if the linked carriers are available in current zone
             if (Carrier::checkCarrierZone($carrier['id_carrier'], $id_zone)) {
                 $carrier_list[] = $carrier['id_carrier'];
             }
         }
         if (empty($carrier_list)) {
             return array();
         }
         //no linked carrier are available for this zone
     }
     // The product is not directly linked with a carrier
     // Get all the carriers linked to a warehouse
     if ($warehouse_id) {
         $warehouse = new JeproshopWarehouseModelWarehouse($warehouse_id);
         $warehouse_carrier_list = $warehouse->getCarriers();
     }
     $available_carrier_list = array();
     $customer = new JeproshopCustomerModelCustomer($cart->customer_id);
     $carriers = JeproshopCarrierModelCarrier::getCarriersForOrder($zone_id, $customer->getGroups(), $cart);
     foreach ($carriers as $carrier) {
         $available_carrier_list[] = $carrier->carrier_id;
     }
     if ($carrier_list) {
         $carrier_list = array_intersect($available_carrier_list, $carrier_list);
     } else {
         $carrier_list = $available_carrier_list;
     }
     if (isset($warehouse_carrier_list)) {
         $carrier_list = array_intersect($carrier_list, $warehouse_carrier_list);
     }
     if ($product->width > 0 || $product->height > 0 || $product->depth > 0 || $product->weight > 0) {
         foreach ($carrier_list as $key => $carrier_id) {
             $carrier = new JeproshopCarrierModelCarrier($carrier_id);
             if ($carrier->max_width > 0 && $carrier->max_width < $product->width || $carrier->max_height > 0 && $carrier->max_height < $product->height || $carrier->max_depth > 0 && $carrier->max_depth < $product->depth || $carrier->max_weight > 0 && $carrier->max_weight < $product->weight) {
                 unset($carrier_list[$key]);
             }
         }
     }
     return $carrier_list;
 }