Newwebshop/classes/Cart.php

1519 lines
46 KiB
PHP

<?php
/**
* Cart class - manages shopping cart functionality
*/
class Cart extends ObjectModel
{
/** @var int|null */
public $id;
/** @var int */
public $id_shop_group;
/** @var int */
public $id_shop;
/** @var int|null */
public $id_address_delivery;
/** @var int|null */
public $id_address_invoice;
/** @var int */
public $id_currency;
/** @var int */
public $id_customer;
/** @var int */
public $id_guest;
/** @var int */
public $id_lang;
/** @var bool */
public $recyclable = false;
/** @var bool */
public $gift = false;
/** @var string */
public $gift_message;
/** @var bool */
public $mobile_theme = false;
/** @var string */
public $date_add;
/** @var string */
public $secure_key;
/** @var int */
public $id_carrier = 0;
/** @var string */
public $date_upd;
/** @var bool */
public $checkedTos = false;
/** @var string */
public $delivery_option;
/** @var bool */
public $allow_seperated_package = false;
// Static cache properties
protected static $_nbProducts = [];
protected static $_isVirtualCart = [];
protected static $_totalWeight = [];
protected static $_carriers = null;
protected static $_taxes_rate = null;
protected static $_attributesLists = [];
/** @var Customer|null */
protected static $_customer = null;
// Cache properties
protected static $cacheDeliveryOption = [];
protected static $cacheNbPackages = [];
protected static $cachePackageList = [];
protected static $cacheDeliveryOptionList = [];
// Constants
public const ONLY_PRODUCTS = 1;
public const ONLY_DISCOUNTS = 2;
public const BOTH = 3;
public const BOTH_WITHOUT_SHIPPING = 4;
public const ONLY_SHIPPING = 5;
public const ONLY_WRAPPING = 6;
public const ONLY_PHYSICAL_PRODUCTS_WITHOUT_SHIPPING = 8;
/**
* @see ObjectModel::$definition
*/
public static $definition = [
'table' => '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;
}
}