'cart', 'primary' => 'id_cart', 'fields' => [ 'id_shop_group' => ['type' => self::TYPE_INT, 'validate' => 'isUnsignedId'], 'id_shop' => ['type' => self::TYPE_INT, 'validate' => 'isUnsignedId'], 'id_address_delivery' => ['type' => self::TYPE_INT, 'validate' => 'isUnsignedId'], 'id_address_invoice' => ['type' => self::TYPE_INT, 'validate' => 'isUnsignedId'], 'id_carrier' => ['type' => self::TYPE_INT, 'validate' => 'isUnsignedId'], 'id_currency' => ['type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true], 'id_customer' => ['type' => self::TYPE_INT, 'validate' => 'isUnsignedId'], 'id_guest' => ['type' => self::TYPE_INT, 'validate' => 'isUnsignedId'], 'id_lang' => ['type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true], 'recyclable' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool'], 'gift' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool'], 'gift_message' => ['type' => self::TYPE_STRING, 'validate' => 'isCleanHtml'], 'mobile_theme' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool'], 'delivery_option' => ['type' => self::TYPE_STRING], 'secure_key' => ['type' => self::TYPE_STRING, 'size' => 32], 'allow_seperated_package' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool'], 'date_add' => ['type' => self::TYPE_DATE, 'validate' => 'isDate'], 'date_upd' => ['type' => self::TYPE_DATE, 'validate' => 'isDate'], ], ]; /** * Reset static cache */ public static function resetStaticCache() { self::$_nbProducts = []; self::$_isVirtualCart = []; self::$_totalWeight = []; self::$_carriers = null; self::$_taxes_rate = null; self::$_attributesLists = []; self::$_customer = null; self::$cacheDeliveryOption = []; self::$cacheNbPackages = []; self::$cachePackageList = []; self::$cacheDeliveryOptionList = []; } /** * Get number of products in cart * * @return int */ public function nbProducts() { if (!$this->id) { return 0; } return self::getNbProducts($this->id); } /** * Get number of products in cart by ID * * @param int $id * @return int */ public static function getNbProducts($id) { if (isset(self::$_nbProducts[$id]) && self::$_nbProducts[$id] !== null) { return self::$_nbProducts[$id]; } self::$_nbProducts[$id] = (int) Db::getInstance()->getValue( 'SELECT SUM(`quantity`) FROM `' . _DB_PREFIX_ . 'cart_product` WHERE `id_cart` = ' . (int) $id ); return self::$_nbProducts[$id]; } /** * Add a CartRule to the Cart * * @param int $id_cart_rule * @param bool $useOrderPrices * @return bool */ public function addCartRule($id_cart_rule, bool $useOrderPrices = false) { $cartRule = new CartRule($id_cart_rule, Context::getContext()->language->id); if (!Validate::isLoadedObject($cartRule)) { return false; } if (Db::getInstance()->getValue('SELECT id_cart_rule FROM ' . _DB_PREFIX_ . 'cart_cart_rule WHERE id_cart_rule = ' . (int) $id_cart_rule . ' AND id_cart = ' . (int) $this->id)) { return false; } if (!Db::getInstance()->insert('cart_cart_rule', [ 'id_cart_rule' => (int) $id_cart_rule, 'id_cart' => (int) $this->id, ])) { return false; } Cache::clean('Cart::getCartRules_' . $this->id . '-' . CartRule::FILTER_ACTION_ALL); Cache::clean('Cart::getCartRules_' . $this->id . '-' . CartRule::FILTER_ACTION_SHIPPING); Cache::clean('Cart::getCartRules_' . $this->id . '-' . CartRule::FILTER_ACTION_REDUCTION); Cache::clean('Cart::getCartRules_' . $this->id . '-' . CartRule::FILTER_ACTION_GIFT); if ((int) $cartRule->gift_product) { $this->updateQty( 1, $cartRule->gift_product, $cartRule->gift_product_attribute, false, 'up', 0, null, false, false, true, $useOrderPrices ); } return true; } /** * Get product quantity in cart * * @param int $idProduct * @param int $idProductAttribute * @param int $idCustomization * @param int $idAddressDelivery * @return array */ public function getProductQuantity($idProduct, $idProductAttribute = 0, $idCustomization = 0, $idAddressDelivery = 0) { $sql = 'SELECT SUM(cp.`quantity`) as quantity FROM `' . _DB_PREFIX_ . 'cart_product` cp WHERE cp.`id_product` = ' . (int) $idProduct . ' AND cp.`id_product_attribute` = ' . (int) $idProductAttribute . ' AND cp.`id_customization` = ' . (int) $idCustomization . ' AND cp.`id_cart` = ' . (int) $this->id; if ($idAddressDelivery) { $sql .= ' AND cp.`id_address_delivery` = ' . (int) $idAddressDelivery; } $result = Db::getInstance()->getRow($sql); return [ 'quantity' => (int) $result['quantity'], 'deep_quantity' => (int) $result['quantity'] ]; } /** * Update product quantity * * @param int $quantity * @param int $id_product * @param int|null $id_product_attribute * @param int|false $id_customization * @param string $operator * @param int $id_address_delivery * @param Shop|null $shop * @param bool $auto_add_cart_rule * @param bool $skipAvailabilityCheckOutOfStock * @param bool $preserveGiftRemoval * @param bool $useOrderPrices * @return bool|int */ 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, $skipAvailabilityCheckOutOfStock = false, bool $preserveGiftRemoval = true, bool $useOrderPrices = false ) { if (!$shop) { $shop = Context::getContext()->shop; } $quantity = (int) $quantity; $id_product = (int) $id_product; $id_product_attribute = (int) $id_product_attribute; $id_customization = (int) $id_customization; $product = new Product($id_product, false, (int) Configuration::get('PS_LANG_DEFAULT'), $shop->id); if (!Validate::isLoadedObject($product)) { return false; } if ($id_product_attribute) { $combination = new Combination((int) $id_product_attribute); if ($combination->id_product != $id_product) { return false; } } $currentQuantity = $this->getProductQuantity($id_product, $id_product_attribute, $id_customization, $id_address_delivery); $currentQuantity = (int) $currentQuantity['quantity']; if ($operator == 'up') { $newQuantity = $currentQuantity + $quantity; } elseif ($operator == 'down') { $newQuantity = $currentQuantity - $quantity; } else { $newQuantity = $quantity; } if ($newQuantity <= 0) { return $this->deleteProduct($id_product, $id_product_attribute, $id_customization, $id_address_delivery, $preserveGiftRemoval, $useOrderPrices); } // Check if product exists in cart $sql = 'SELECT `id_cart_product` FROM `' . _DB_PREFIX_ . 'cart_product` WHERE `id_cart` = ' . (int) $this->id . ' AND `id_product` = ' . (int) $id_product . ' AND `id_product_attribute` = ' . (int) $id_product_attribute . ' AND `id_customization` = ' . (int) $id_customization; if ($id_address_delivery) { $sql .= ' AND `id_address_delivery` = ' . (int) $id_address_delivery; } $result = Db::getInstance()->getRow($sql); if ($result) { // Update existing product $sql = 'UPDATE `' . _DB_PREFIX_ . 'cart_product` SET `quantity` = ' . (int) $newQuantity . ' WHERE `id_cart_product` = ' . (int) $result['id_cart_product']; } else { // Add new product $sql = 'INSERT INTO `' . _DB_PREFIX_ . 'cart_product` (`id_cart`, `id_product`, `id_product_attribute`, `id_customization`, `id_address_delivery`, `quantity`) VALUES (' . (int) $this->id . ', ' . (int) $id_product . ', ' . (int) $id_product_attribute . ', ' . (int) $id_customization . ', ' . (int) $id_address_delivery . ', ' . (int) $newQuantity . ')'; } if (!Db::getInstance()->execute($sql)) { return false; } // Clear cache self::$_nbProducts[$this->id] = null; self::$_totalWeight[$this->id] = null; return $newQuantity; } /** * Delete product from cart * * @param int $id_product * @param int $id_product_attribute * @param int $id_customization * @param int $id_address_delivery * @param bool $preserveGiftsRemoval * @param bool $useOrderPrices * @return bool */ public function deleteProduct( $id_product, $id_product_attribute = 0, $id_customization = 0, $id_address_delivery = 0, bool $preserveGiftsRemoval = true, bool $useOrderPrices = false ) { $sql = 'DELETE FROM `' . _DB_PREFIX_ . 'cart_product` WHERE `id_cart` = ' . (int) $this->id . ' AND `id_product` = ' . (int) $id_product . ' AND `id_product_attribute` = ' . (int) $id_product_attribute . ' AND `id_customization` = ' . (int) $id_customization; if ($id_address_delivery) { $sql .= ' AND `id_address_delivery` = ' . (int) $id_address_delivery; } if (!Db::getInstance()->execute($sql)) { return false; } // Clear cache self::$_nbProducts[$this->id] = null; self::$_totalWeight[$this->id] = null; return true; } /** * Get order total * * @param bool $withTaxes * @param int $type * @param array|null $products * @param int|null $id_carrier * @param bool $use_cache * @param bool $keepOrderPrices * @return float */ public function getOrderTotal( $withTaxes = true, $type = self::BOTH, $products = null, $id_carrier = null, $use_cache = false, bool $keepOrderPrices = false ) { $total = 0; if ($type == self::ONLY_PRODUCTS || $type == self::BOTH || $type == self::BOTH_WITHOUT_SHIPPING) { $products = $this->getProducts($use_cache, false, null, true, $keepOrderPrices); foreach ($products as $product) { $price = $product['price_with_reduction']; if (!$withTaxes) { $price = $product['price_with_reduction_without_tax']; } $total += $price * $product['cart_quantity']; } } if ($type == self::ONLY_DISCOUNTS || $type == self::BOTH) { $discounts = $this->getDiscounts(); foreach ($discounts as $discount) { $total -= $discount['value_real']; } } if ($type == self::ONLY_SHIPPING || $type == self::BOTH) { if ($id_carrier) { $total += $this->getCarrierCost($id_carrier, $withTaxes); } } if ($type == self::ONLY_WRAPPING || $type == self::BOTH) { if ($this->gift) { $total += $this->getGiftWrappingPrice($withTaxes); } } return Tools::ps_round($total, 2); } /** * Get total weight * * @param array|null $products * @return float */ public function getTotalWeight($products = null) { if (!$this->id) { return 0; } if (isset(self::$_totalWeight[$this->id])) { return self::$_totalWeight[$this->id]; } if ($products === null) { $products = $this->getProducts(); } $weight = 0; foreach ($products as $product) { $weight += $product['weight'] * $product['cart_quantity']; } self::$_totalWeight[$this->id] = $weight; return $weight; } /** * Check if cart is virtual (only virtual products) * * @return bool */ public function isVirtualCart() { if (!$this->id) { return true; } if (isset(self::$_isVirtualCart[$this->id])) { return self::$_isVirtualCart[$this->id]; } $sql = 'SELECT COUNT(*) FROM `' . _DB_PREFIX_ . 'cart_product` cp LEFT JOIN `' . _DB_PREFIX_ . 'product` p ON cp.`id_product` = p.`id_product` WHERE cp.`id_cart` = ' . (int) $this->id . ' AND p.`is_virtual` = 0'; $result = Db::getInstance()->getValue($sql); $isVirtual = ($result == 0); self::$_isVirtualCart[$this->id] = $isVirtual; return $isVirtual; } /** * Check if cart has products * * @return bool */ public function hasProducts() { if (!$this->id) { return false; } return (bool) Db::getInstance()->getValue( 'SELECT COUNT(*) FROM `' . _DB_PREFIX_ . 'cart_product` WHERE `id_cart` = ' . (int) $this->id ); } /** * Check if cart has real products * * @return bool */ public function hasRealProducts() { if (!$this->id) { return false; } $sql = 'SELECT COUNT(*) FROM `' . _DB_PREFIX_ . 'cart_product` cp LEFT JOIN `' . _DB_PREFIX_ . 'product` p ON cp.`id_product` = p.`id_product` WHERE cp.`id_cart` = ' . (int) $this->id . ' AND p.`is_virtual` = 0'; return (bool) Db::getInstance()->getValue($sql); } /** * Get carrier cost * * @param int $id_carrier * @param bool $useTax * @param Country|null $default_country * @param string|null $delivery_option * @return float */ public function getCarrierCost($id_carrier, $useTax = true, ?Country $default_country = null, $delivery_option = null) { // Simplified carrier cost calculation $carrier = new Carrier($id_carrier); if (!Validate::isLoadedObject($carrier)) { return 0; } $cost = $carrier->getDeliveryPriceByWeight($this->getTotalWeight()); if ($useTax) { $tax = new Tax($carrier->getIdTaxRulesGroup()); if (Validate::isLoadedObject($tax)) { $cost += $cost * ($tax->rate / 100); } } return Tools::ps_round($cost, 2); } /** * Get gift wrapping price * * @param bool $with_taxes * @param int|null $id_address * @return float */ public function getGiftWrappingPrice($with_taxes = true, $id_address = null) { $wrapping_fees = (float) Configuration::get('PS_GIFT_WRAPPING_PRICE'); if ($with_taxes) { $tax = new Tax(Configuration::get('PS_GIFT_WRAPPING_TAX_RULES_GROUP')); if (Validate::isLoadedObject($tax)) { $wrapping_fees += $wrapping_fees * ($tax->rate / 100); } } return Tools::ps_round($wrapping_fees, 2); } /** * Get last none ordered cart * * @param int $id_customer * @return int|false */ public static function lastNoneOrderedCart($id_customer) { $sql = 'SELECT c.`id_cart` FROM `' . _DB_PREFIX_ . 'cart` c LEFT JOIN `' . _DB_PREFIX_ . 'orders` o ON c.`id_cart` = o.`id_cart` WHERE c.`id_customer` = ' . (int) $id_customer . ' AND o.`id_cart` IS NULL ORDER BY c.`date_add` DESC'; return Db::getInstance()->getValue($sql); } /** * Get customer carts * * @param int $id_customer * @param bool $with_order * @return array */ public static function getCustomerCarts($id_customer, $with_order = true) { $sql = 'SELECT c.* FROM `' . _DB_PREFIX_ . 'cart` c'; if ($with_order) { $sql .= ' LEFT JOIN `' . _DB_PREFIX_ . 'orders` o ON c.`id_cart` = o.`id_cart` WHERE c.`id_customer` = ' . (int) $id_customer . ' AND o.`id_cart` IS NULL'; } else { $sql .= ' WHERE c.`id_customer` = ' . (int) $id_customer; } $sql .= ' ORDER BY c.`date_add` DESC'; return Db::getInstance()->executeS($sql); } /** * Check quantities * * @param bool $returnProductOnFailure * @return bool|array */ public function checkQuantities($returnProductOnFailure = false) { $products = $this->getProducts(); $errors = []; foreach ($products as $product) { if (!$product['active'] || !$product['available_for_order']) { $errors[] = $product; continue; } if ($product['quantity'] < $product['cart_quantity']) { $errors[] = $product; } } if ($returnProductOnFailure) { return $errors; } return empty($errors); } /** * Get products * * @param bool $refresh * @param bool $id_product * @param int|null $id_country * @param bool $fullInfos * @param bool $keepOrderPrices * @return array */ public function getProducts($refresh = false, $id_product = false, $id_country = null, $fullInfos = true, bool $keepOrderPrices = false) { if (!$this->id) { return []; } $sql = 'SELECT cp.*, p.*, pl.*, i.`id_image`, cl.`name` as category_default FROM `' . _DB_PREFIX_ . 'cart_product` cp LEFT JOIN `' . _DB_PREFIX_ . 'product` p ON cp.`id_product` = p.`id_product` LEFT JOIN `' . _DB_PREFIX_ . 'product_lang` pl ON p.`id_product` = pl.`id_product` AND pl.`id_lang` = ' . (int) $this->id_lang . ' LEFT JOIN `' . _DB_PREFIX_ . 'image` i ON p.`id_product` = i.`id_product` AND i.`cover` = 1 LEFT JOIN `' . _DB_PREFIX_ . 'category_lang` cl ON p.`id_category_default` = cl.`id_category` AND cl.`id_lang` = ' . (int) $this->id_lang . ' WHERE cp.`id_cart` = ' . (int) $this->id; if ($id_product) { $sql .= ' AND cp.`id_product` = ' . (int) $id_product; } $sql .= ' ORDER BY cp.`date_add` ASC'; $products = Db::getInstance()->executeS($sql); if (!$products) { return []; } foreach ($products as &$product) { $product['price_with_reduction'] = $product['price']; $product['price_with_reduction_without_tax'] = $product['price']; $product['total'] = $product['price'] * $product['cart_quantity']; $product['total_wt'] = $product['price'] * $product['cart_quantity']; } return $products; } /** * Get discounts * * @return array */ public function getDiscounts() { $sql = 'SELECT cr.*, crl.`name` FROM `' . _DB_PREFIX_ . 'cart_cart_rule` ccr LEFT JOIN `' . _DB_PREFIX_ . 'cart_rule` cr ON ccr.`id_cart_rule` = cr.`id_cart_rule` LEFT JOIN `' . _DB_PREFIX_ . 'cart_rule_lang` crl ON cr.`id_cart_rule` = crl.`id_cart_rule` AND crl.`id_lang` = ' . (int) $this->id_lang . ' WHERE ccr.`id_cart` = ' . (int) $this->id . ' AND cr.`active` = 1'; return Db::getInstance()->executeS($sql); } // Erweiterte Cart-Funktionen public function setTaxCalculationMethod() { $this->_taxCalculationMethod = Configuration::get('PS_TAX'); } public function updateAddressId($id_address, $id_address_new) { $sql = 'UPDATE ' . _DB_PREFIX_ . 'cart_product SET id_address_delivery = ' . (int) $id_address_new . ' WHERE id_cart = ' . (int) $this->id . ' AND id_address_delivery = ' . (int) $id_address; return Db::getInstance()->execute($sql); } public function updateDeliveryAddressId($currentAddressId, $newAddressId) { $sql = 'UPDATE ' . _DB_PREFIX_ . 'cart_product SET id_address_delivery = ' . (int) $newAddressId . ' WHERE id_cart = ' . (int) $this->id . ' AND id_address_delivery = ' . (int) $currentAddressId; return Db::getInstance()->execute($sql); } public function getCartRules($filter = CartRule::FILTER_ACTION_ALL, $autoAdd = true, $useOrderPrices = false) { $sql = 'SELECT cr.*, crl.* FROM ' . _DB_PREFIX_ . 'cart_cart_rule ccr LEFT JOIN ' . _DB_PREFIX_ . 'cart_rule cr ON (ccr.id_cart_rule = cr.id_cart_rule) LEFT JOIN ' . _DB_PREFIX_ . 'cart_rule_lang crl ON (cr.id_cart_rule = crl.id_cart_rule AND crl.id_lang = ' . (int) Context::getContext()->language->id . ') WHERE ccr.id_cart = ' . (int) $this->id; return Db::getInstance()->executeS($sql); } public function getOrderedCartRulesIds($filter = CartRule::FILTER_ACTION_ALL) { $sql = 'SELECT id_cart_rule FROM ' . _DB_PREFIX_ . 'cart_cart_rule WHERE id_cart = ' . (int) $this->id; return Db::getInstance()->executeS($sql); } public function getDiscountsCustomer($id_cart_rule) { $sql = 'SELECT * FROM ' . _DB_PREFIX_ . 'cart_cart_rule WHERE id_cart_rule = ' . (int) $id_cart_rule . ' AND id_cart = ' . (int) $this->id; return Db::getInstance()->executeS($sql); } public function getLastProduct() { $sql = 'SELECT cp.*, p.*, pl.* FROM ' . _DB_PREFIX_ . 'cart_product cp LEFT JOIN ' . _DB_PREFIX_ . 'product p ON (cp.id_product = p.id_product) LEFT JOIN ' . _DB_PREFIX_ . 'product_lang pl ON (p.id_product = pl.id_product AND pl.id_lang = ' . (int) Context::getContext()->language->id . ') WHERE cp.id_cart = ' . (int) $this->id . ' ORDER BY cp.date_add DESC LIMIT 1'; return Db::getInstance()->getRow($sql); } public function removeCartRule($id_cart_rule, $useOrderPrices = false) { $sql = 'DELETE FROM ' . _DB_PREFIX_ . 'cart_cart_rule WHERE id_cart_rule = ' . (int) $id_cart_rule . ' AND id_cart = ' . (int) $this->id; return Db::getInstance()->execute($sql); } public function orderExists() { $sql = 'SELECT id_order FROM ' . _DB_PREFIX_ . 'orders WHERE id_cart = ' . (int) $this->id; return (bool) Db::getInstance()->getValue($sql); } public function _addCustomization($id_product, $id_product_attribute, $index, $type, $value, $quantity, $returnId = false) { $customization = [ 'id_product' => (int) $id_product, 'id_product_attribute' => (int) $id_product_attribute, 'id_cart' => (int) $this->id, 'quantity' => (int) $quantity, 'type' => (int) $type, 'index' => (int) $index, ]; if ($type == Product::CUSTOMIZE_TEXTFIELD) { $customization['value'] = pSQL($value); } elseif ($type == Product::CUSTOMIZE_FILE) { $customization['value'] = pSQL($value); } $id_customization = Db::getInstance()->insert('customization', $customization); if ($returnId) { return $id_customization; } return true; } public function getTotalCart($id_cart, $use_tax_display = false, $type = Cart::BOTH) { $cart = new Cart($id_cart); return $cart->getOrderTotal($use_tax_display, $type); } public function getOrderTotalUsingTaxCalculationMethod($id_cart) { $cart = new Cart($id_cart); return $cart->getOrderTotal(true, Cart::BOTH); } public function newCalculator($products, $cartRules, $id_carrier, $computePrecision = null, $keepOrderPrices = false) { // Calculator-Implementierung return new Calculator($products, $cartRules, $id_carrier, $computePrecision, $keepOrderPrices); } public function getDiscountSubtotalWithoutGifts($withTaxes = true) { $products = $this->getProducts(); $subtotal = 0; foreach ($products as $product) { if (!$product['is_gift']) { $subtotal += $product['total_price']; } } return $subtotal; } public function countProductLines($products) { return count($products); } public function getDeliveryAddressId($products = null) { if (!$products) { $products = $this->getProducts(); } if (count($products) == 0) { return 0; } return (int) $products[0]['id_address_delivery']; } public function getTotalCalculationCartRules($type, $withShipping) { $cartRules = $this->getCartRules(); $total = 0; foreach ($cartRules as $cartRule) { if ($cartRule['free_shipping'] && $withShipping) { $total += $this->getCarrierCost($this->id_carrier); } else { $total += $cartRule['value_real']; } } return $total; } public function findTaxRulesGroupId($withTaxes, $product, $virtualContext) { if ($withTaxes) { return $product['id_tax_rules_group']; } return 0; } public function getProductAddressId($product = null) { if (!$product) { $products = $this->getProducts(); if (count($products) == 0) { return 0; } $product = $products[0]; } return (int) $product['id_address_delivery']; } public function getTaxAddressId() { return $this->getProductAddressId(); } public function calculateWrappingFees($withTaxes, $type) { if ($this->gift) { $wrapping_fees = Configuration::get('PS_GIFT_WRAPPING_PRICE'); if ($withTaxes) { $wrapping_fees *= (1 + (Configuration::get('PS_GIFT_WRAPPING_TAX_RATE') / 100)); } return $wrapping_fees; } return 0; } public function getNbOfPackages() { $products = $this->getProducts(); $package_list = []; foreach ($products as $product) { $package_list[$product['id_address_delivery']][] = $product; } return count($package_list); } public function getPackageList($flush = false) { $products = $this->getProducts(); $package_list = []; foreach ($products as $product) { $package_list[$product['id_address_delivery']][] = $product; } return $package_list; } public function getPackageIdWarehouse($package, $id_carrier = null) { $warehouse_list = []; foreach ($package as $product) { $warehouse_list[] = $product['id_warehouse']; } return array_unique($warehouse_list); } public function getDeliveryOptionList($default_country = null, $flush = false) { $delivery_option_list = []; if (!$default_country) { $default_country = Context::getContext()->country; } $carriers = Carrier::getCarriers(Context::getContext()->language->id, true, false, false, null, Carrier::ALL_CARRIERS); foreach ($carriers as $carrier) { $delivery_option_list[$carrier['id_carrier']] = [ 'id_carrier' => $carrier['id_carrier'], 'name' => $carrier['name'], 'delay' => $carrier['delay'], 'price' => $this->getCarrierCost($carrier['id_carrier']), ]; } return $delivery_option_list; } public static function sortDeliveryOptionList($option1, $option2) { if ($option1['price'] == $option2['price']) { return 0; } return ($option1['price'] < $option2['price']) ? -1 : 1; } public function carrierIsSelected($id_carrier, $id_address) { return $this->id_carrier == $id_carrier; } public function simulateCarrierSelectedOutput($use_cache = true) { $delivery_option = $this->getDeliveryOption(); $delivery_option_list = $this->getDeliveryOptionList(); foreach ($delivery_option_list as $id_carrier => $option) { if (isset($delivery_option[$id_carrier])) { return $delivery_option[$id_carrier]; } } return false; } public static function intifier($string, $delimiter = ',') { $array = explode($delimiter, $string); $array = array_map('intval', $array); return $array; } public static function desintifier($int, $delimiter = ',') { if (is_array($int)) { return implode($delimiter, $int); } return $int; } public function isMultiAddressDelivery() { $products = $this->getProducts(); $addresses = []; foreach ($products as $product) { $addresses[] = $product['id_address_delivery']; } return count(array_unique($addresses)) > 1; } public function getAddressCollection() { $addresses = []; $products = $this->getProducts(); foreach ($products as $product) { $addresses[] = new Address($product['id_address_delivery']); } return $addresses; } public function setDeliveryOption($delivery_option = null) { if (!$delivery_option) { $delivery_option = $this->getDeliveryOption(); } $this->delivery_option = serialize($delivery_option); $this->id_carrier = $this->getIdCarrierFromDeliveryOption($delivery_option); return $this->update(); } protected function getIdCarrierFromDeliveryOption($delivery_option) { if (is_array($delivery_option)) { foreach ($delivery_option as $id_carrier) { return (int) $id_carrier; } } return (int) $delivery_option; } public function getDeliveryOption($default_country = null, $dontAutoSelectOptions = false, $use_cache = true) { if (!$default_country) { $default_country = Context::getContext()->country; } $delivery_option_list = $this->getDeliveryOptionList($default_country); if ($dontAutoSelectOptions) { return $delivery_option_list; } // Auto-select first option foreach ($delivery_option_list as $id_carrier => $option) { return [$id_carrier => $option]; } return []; } public function getTotalShippingCost($delivery_option = null, $use_tax = true, $default_country = null) { if (!$delivery_option) { $delivery_option = $this->getDeliveryOption(); } $total_shipping = 0; foreach ($delivery_option as $id_carrier => $option) { $total_shipping += $this->getCarrierCost($id_carrier, $use_tax, $default_country); } return $total_shipping; } public function getPackageShippingCost($id_carrier = null, $use_tax = true, $default_country = null, $product_list = null, $id_zone = null, $keepOrderPrices = false) { if (!$id_carrier) { $id_carrier = $this->id_carrier; } return $this->getPackageShippingCostValue($id_carrier, $use_tax, $default_country, $product_list, $id_zone, $keepOrderPrices); } protected function getPackageShippingCostValue($id_carrier = null, $use_tax = true, $default_country = null, $product_list = null, $id_zone = null, $keepOrderPrices = false) { if (!$id_carrier) { $id_carrier = $this->id_carrier; } if (!$product_list) { $product_list = $this->getProducts(); } if (!$default_country) { $default_country = Context::getContext()->country; } $carrier = new Carrier($id_carrier); $shipping_cost = $carrier->getShippingCost($this->getTotalWeight($product_list), $default_country); if ($use_tax) { $shipping_cost *= (1 + ($carrier->getTaxesRate($default_country) / 100)); } return $shipping_cost; } protected function getPackageShippingCostFromModule($carrier, $shipping_cost, $products) { // Module-spezifische Versandkosten return $shipping_cost; } protected function updateProductWeight($productId) { $product = new Product($productId); $weight = $product->weight; $sql = 'UPDATE ' . _DB_PREFIX_ . 'cart_product SET weight = ' . (float) $weight . ' WHERE id_cart = ' . (int) $this->id . ' AND id_product = ' . (int) $productId; return Db::getInstance()->execute($sql); } public function getSummaryDetails($id_lang = null, $refresh = false) { if (!$id_lang) { $id_lang = Context::getContext()->language->id; } $summary = [ 'products' => $this->getProducts(), 'total_products' => $this->getOrderTotal(false, Cart::ONLY_PRODUCTS), 'total_discounts' => $this->getOrderTotal(false, Cart::ONLY_DISCOUNTS), 'total_wrapping' => $this->getOrderTotal(false, Cart::ONLY_WRAPPING), 'total_shipping' => $this->getOrderTotal(true, Cart::ONLY_SHIPPING), 'total_price' => $this->getOrderTotal(true, Cart::BOTH), 'total_tax' => $this->getOrderTotal(true, Cart::BOTH) - $this->getOrderTotal(false, Cart::BOTH), ]; return $summary; } public function getRawSummaryDetails($id_lang, $refresh = false) { return $this->getSummaryDetails($id_lang, $refresh); } public function checkProductsAccess() { $products = $this->getProducts(); foreach ($products as $product) { if (!$product['active']) { return false; } } return true; } public static function getCartByOrderId($id_order) { $sql = 'SELECT id_cart FROM ' . _DB_PREFIX_ . 'orders WHERE id_order = ' . (int) $id_order; return Db::getInstance()->getValue($sql); } public static function getCartIdByOrderId($id_order) { return self::getCartByOrderId($id_order); } public function addTextFieldToProduct($id_product, $index, $type, $text_value, $returnCustomizationId = false) { return $this->_addCustomization($id_product, 0, $index, $type, $text_value, 1, $returnCustomizationId); } public function addPictureToProduct($id_product, $index, $type, $file, $returnCustomizationId = false) { return $this->_addCustomization($id_product, 0, $index, $type, $file, 1, $returnCustomizationId); } public function deleteCustomizationToProduct($id_product, $index) { $sql = 'DELETE FROM ' . _DB_PREFIX_ . 'customization WHERE id_cart = ' . (int) $this->id . ' AND id_product = ' . (int) $id_product . ' AND `index` = ' . (int) $index; return Db::getInstance()->execute($sql); } public function getProductCustomization($id_product, $type = null, $not_in_cart = false) { $sql = 'SELECT * FROM ' . _DB_PREFIX_ . 'customization WHERE id_cart = ' . (int) $this->id . ' AND id_product = ' . (int) $id_product; if ($type !== null) { $sql .= ' AND type = ' . (int) $type; } if ($not_in_cart) { $sql .= ' AND id_customization NOT IN (SELECT id_customization FROM ' . _DB_PREFIX_ . 'cart_product WHERE id_cart = ' . (int) $this->id . ')'; } return Db::getInstance()->executeS($sql); } public function duplicate() { $cart = new Cart(); $cart->id_shop_group = $this->id_shop_group; $cart->id_shop = $this->id_shop; $cart->id_address_delivery = $this->id_address_delivery; $cart->id_address_invoice = $this->id_address_invoice; $cart->id_currency = $this->id_currency; $cart->id_customer = $this->id_customer; $cart->id_guest = $this->id_guest; $cart->id_lang = $this->id_lang; $cart->recyclable = $this->recyclable; $cart->gift = $this->gift; $cart->gift_message = $this->gift_message; $cart->mobile_theme = $this->mobile_theme; $cart->secure_key = $this->secure_key; $cart->id_carrier = $this->id_carrier; $cart->delivery_option = $this->delivery_option; $cart->allow_seperated_package = $this->allow_seperated_package; if ($cart->add()) { $products = $this->getProducts(); foreach ($products as $product) { $cart->updateQty($product['quantity'], $product['id_product'], $product['id_product_attribute']); } return $cart; } return false; } public function getWsCartRows() { $products = $this->getProducts(); $cart_rows = []; foreach ($products as $product) { $cart_rows[] = [ 'id_product' => $product['id_product'], 'id_product_attribute' => $product['id_product_attribute'], 'id_address_delivery' => $product['id_address_delivery'], 'id_customization' => $product['id_customization'], 'quantity' => $product['quantity'], ]; } return $cart_rows; } public function setWsCartRows($values) { // Bestehende Produkte löschen Db::getInstance()->delete('cart_product', 'id_cart = ' . (int) $this->id); // Neue Produkte hinzufügen foreach ($values as $value) { $data = [ 'id_cart' => (int) $this->id, 'id_product' => (int) $value['id_product'], 'id_product_attribute' => (int) $value['id_product_attribute'], 'id_address_delivery' => (int) $value['id_address_delivery'], 'id_customization' => (int) $value['id_customization'], 'quantity' => (int) $value['quantity'], ]; Db::getInstance()->insert('cart_product', $data); } return true; } public function setProductAddressDelivery($id_product, $id_product_attribute, $old_id_address_delivery, $new_id_address_delivery) { $sql = 'UPDATE ' . _DB_PREFIX_ . 'cart_product SET id_address_delivery = ' . (int) $new_id_address_delivery . ' WHERE id_cart = ' . (int) $this->id . ' AND id_product = ' . (int) $id_product . ' AND id_product_attribute = ' . (int) $id_product_attribute . ' AND id_address_delivery = ' . (int) $old_id_address_delivery; return Db::getInstance()->execute($sql); } public function setProductCustomizedDatas(&$product, $customized_datas) { $product['customizedDatas'] = $customized_datas; } public function duplicateProduct($id_product, $id_product_attribute, $id_address_delivery, $new_id_address_delivery, $quantity = 1, $keep_quantity = false) { $data = [ 'id_cart' => (int) $this->id, 'id_product' => (int) $id_product, 'id_product_attribute' => (int) $id_product_attribute, 'id_address_delivery' => (int) $new_id_address_delivery, 'quantity' => (int) $quantity, ]; return Db::getInstance()->insert('cart_product', $data); } public function setNoMultishipping() { $this->allow_seperated_package = false; return $this->update(); } public function autosetProductAddress() { $products = $this->getProducts(); if (count($products) == 0) { return; } $id_address_delivery = $products[0]['id_address_delivery']; $sql = 'UPDATE ' . _DB_PREFIX_ . 'cart_product SET id_address_delivery = ' . (int) $id_address_delivery . ' WHERE id_cart = ' . (int) $this->id; Db::getInstance()->execute($sql); } public function deleteAssociations() { return Db::getInstance()->delete('cart_product', 'id_cart = ' . (int) $this->id); } public function isCarrierInRange($id_carrier, $id_zone) { $carrier = new Carrier($id_carrier); return $carrier->getZone($id_zone); } public static function isGuestCartByCartId($id_cart) { $sql = 'SELECT id_guest FROM ' . _DB_PREFIX_ . 'cart WHERE id_cart = ' . (int) $id_cart; return (bool) Db::getInstance()->getValue($sql); } public function checkAllProductsAreStillAvailableInThisState() { $products = $this->getProducts(); foreach ($products as $product) { if (!$product['active']) { return false; } } return true; } public function isAllProductsInStock($ignoreVirtual = false) { $products = $this->getProducts(); foreach ($products as $product) { if ($ignoreVirtual && $product['is_virtual']) { continue; } if ($product['quantity'] > $product['stock_quantity']) { return false; } } return true; } public function checkAllProductsHaveMinimalQuantities() { $products = $this->getProducts(); foreach ($products as $product) { if ($product['quantity'] < $product['minimal_quantity']) { return false; } } return true; } protected function splitGiftsProductsQuantity() { $this->shouldSplitGiftProductsQuantity = true; } protected function mergeGiftsProductsQuantity() { $this->shouldSplitGiftProductsQuantity = false; } protected function excludeGiftsDiscountFromTotal() { $this->shouldExcludeGiftsDiscount = true; } protected function includeGiftsDiscountInTotal() { $this->shouldExcludeGiftsDiscount = false; } public function getProductsWithSeparatedGifts() { $products = $this->getProducts(); $gifts = []; $regular_products = []; foreach ($products as $product) { if ($product['is_gift']) { $gifts[] = $product; } else { $regular_products[] = $product; } } return [ 'gifts' => $gifts, 'regular_products' => $regular_products, ]; } public function getTaxCountry() { $address = new Address($this->getTaxAddressId()); return new Country($address->id_country); } public function alterSummaryForDisplay($summary, $refresh = false) { // Summary für Anzeige anpassen return $summary; } public function getCartTotalPrice() { return $this->getOrderTotal(true, Cart::BOTH); } public function getProductQuantityInAllVariants($idProduct) { $sql = 'SELECT SUM(quantity) as total_quantity FROM ' . _DB_PREFIX_ . 'cart_product WHERE id_cart = ' . (int) $this->id . ' AND id_product = ' . (int) $idProduct; $result = Db::getInstance()->getRow($sql); return isset($result['total_quantity']) ? (int) $result['total_quantity'] : 0; } }