Skip to content

Commit 4b07033

Browse files
committed
Merge branch '8.1.x' into merge-250324
2 parents 400b612 + d89d0b9 commit 4b07033

File tree

102 files changed

+5234
-4356
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

102 files changed

+5234
-4356
lines changed

.github/actions/setup-env/action.yml

+5
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ inputs:
2626
required: false
2727
description: True to enable Developer mode
2828
default: 'false'
29+
DISABLE_MAKE:
30+
required: false
31+
description: true to disable Make
32+
default: 'false'
2933
BO_LAYOUT:
3034
required: false
3135
description: Choose between Legacy and Symfony layout
@@ -68,6 +72,7 @@ runs:
6872
- name: Build and Run shop with docker
6973
shell: bash
7074
env:
75+
DISABLE_MAKE: ${{ (inputs.DISABLE_MAKE == 'true') && '1' || '0' }}
7176
PS_ENABLE_SSL: ${{ (inputs.ENABLE_SSL == 'true') && '1' || '0' }}
7277
PS_INSTALL_AUTO: ${{ (inputs.INSTALL_AUTO == 'true') && '1' || '0' }}
7378
PS_USE_DOCKER_MAILDEV: 0

CONTRIBUTORS.md

+3
Original file line numberDiff line numberDiff line change
@@ -194,12 +194,14 @@ GitHub contributors:
194194
- Daniel Ziegenberg
195195
- Daniele Giachino
196196
- Daniele Rosario
197+
- Danilo Carta
197198
- Danoosh
198199
- Danoosh Mir
199200
- Dany Maillard
200201
- daresh
201202
- Darius Aleksiunas
202203
- dariusakafest
204+
- Dariusz Tryba
203205
- David D.
204206
- David Diverres
205207
- David Eschmeyer
@@ -357,6 +359,7 @@ GitHub contributors:
357359
- Henri Davigne
358360
- Hervé Hennes
359361
- hhennes
362+
- Hherreros
360363
- Hibatallah Aouadni
361364
- hiousi
362365
- Hitasukha

admin-dev/themes/default/template/controllers/cart_rules/informations.tpl

+1-6
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@
8787
</div>
8888
</div>
8989

90-
<div class="form-group" id="cart-rules-highlight"{if !$currentTab->getFieldValue($currentObject, 'code')} style="display: none;"{/if}>
90+
<div class="form-group">
9191
<label class="control-label col-lg-3">
9292
<span class="label-tooltip" data-toggle="tooltip"
9393
title="{l|escape s='If the voucher is not yet in the cart, it will be displayed in the cart summary.' d='Admin.Catalog.Help'}">
@@ -150,9 +150,4 @@
150150
</div>
151151
<script type="text/javascript">
152152
$(".textarea-autosize").autosize();
153-
$(function() {
154-
$('#code').on('keyup change', function() {
155-
$('#cart-rules-highlight').toggle($(this).val() !== "");
156-
});
157-
});
158153
</script>

admin-dev/themes/default/template/controllers/login/content.tpl

-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
<h1 class="text-center">
2828
<img id="logo" src="{$img_dir}[email protected]" width="123px" height="24px" alt="PrestaShop" />
2929
</h1>
30-
<div class="text-center">{$ps_version}</div>
3130
<div id="error" class="hide alert alert-danger">
3231
{if isset($errors)}
3332
<h4>

classes/Cart.php

+14-2
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,19 @@ public function getProducts($refresh = false, $id_product = false, $id_country =
744744
$reduction_type_row = ['reduction_type' => 0];
745745
}
746746

747+
/*
748+
* In case of packs, we need to properly calculate the quantity in stock. We can't just use
749+
* the quantity from the query, because stocks can be set to use the quantity of the products
750+
* in them. The quantity in stock_available then has no meaning and could be always zero.
751+
*
752+
* When calling Pack::getQuantity here, you MUST use null for $cart parameter. Otherwise it
753+
* will subtract the quantity that is already in the cart. Basically resulting in a nonsense,
754+
* half of quantity you have. We need the REAL quantity.
755+
*/
756+
if (Pack::isPack($product['id_product'])) {
757+
$product['quantity_available'] = Pack::getQuantity((int) $product['id_product'], (int) $product['id_product_attribute']);
758+
}
759+
747760
$products[$key] = array_merge($product, $reduction_type_row);
748761
}
749762
}
@@ -3799,8 +3812,7 @@ public function checkQuantities($returnProductOnFailure = false)
37993812
foreach ($this->getProducts() as $product) {
38003813
if (
38013814
!$product['active'] ||
3802-
!$product['available_for_order'] ||
3803-
(!$product['allow_oosp'] && $product['stock_quantity'] < $product['cart_quantity'])
3815+
!$product['available_for_order']
38043816
) {
38053817
return $returnProductOnFailure ? $product : false;
38063818
}

classes/CartRule.php

+19-14
Original file line numberDiff line numberDiff line change
@@ -368,8 +368,8 @@ public static function haveCartRuleToday($idCustomer)
368368
* @param int $id_lang Language ID
369369
* @param int $id_customer Customer ID
370370
* @param bool $active Active vouchers only
371-
* @param bool $includeGeneric Include generic AND highlighted vouchers, regardless of highlight_only setting
372-
* @param bool $inStock Vouchers in stock only
371+
* @param bool $includeGeneric Include generic vouchers that don't have specific customer
372+
* @param bool $inStock Vouchers that have "total quantity" remaining
373373
* @param CartCore|null $cart Cart
374374
* @param bool $free_shipping_only Free shipping only
375375
* @param bool $highlight_only Highlighted vouchers only
@@ -392,31 +392,36 @@ public static function getCustomerCartRules(
392392
return [];
393393
}
394394

395-
$sql_part1 = '* FROM `' . _DB_PREFIX_ . 'cart_rule` cr
396-
LEFT JOIN `' . _DB_PREFIX_ . 'cart_rule_lang` crl ON (cr.`id_cart_rule` = crl.`id_cart_rule` AND crl.`id_lang` = ' . (int) $id_lang . ')';
395+
// Basic part of the query, we are selecting all cart rules
396+
$sql = '
397+
SELECT SQL_NO_CACHE * FROM `' . _DB_PREFIX_ . 'cart_rule` cr
398+
LEFT JOIN `' . _DB_PREFIX_ . 'cart_rule_lang` crl
399+
ON (cr.`id_cart_rule` = crl.`id_cart_rule` AND crl.`id_lang` = ' . (int) $id_lang . ')';
397400

398-
$sql_where = ' WHERE ((cr.`id_customer` = ' . (int) $id_customer . ' OR (cr.`id_customer` = 0 AND (cr.`highlight` = 1 OR cr.`code` = "")))';
401+
// We will definitely include vouchers for this specific customer
402+
$sql .= ' WHERE (cr.`id_customer` = ' . (int) $id_customer;
399403

404+
// And if required, all the generic ones, that don't have any specific customer set
400405
if ($includeGeneric && (int) $id_customer !== 0) {
401-
$sql_where .= ' OR cr.`id_customer` = 0)';
402-
} else {
403-
$sql_where .= ')';
406+
$sql .= ' OR cr.`id_customer` = 0';
404407
}
408+
$sql .= ')';
405409

406-
$sql_part2 = ' AND NOW() BETWEEN cr.date_from AND cr.date_to
410+
// Then, conditions for date, voucher active property and total amount of vouchers in stock
411+
$sql .= ' AND NOW() BETWEEN cr.date_from AND cr.date_to
407412
' . ($active ? 'AND cr.`active` = 1' : '') . '
408413
' . ($inStock ? 'AND cr.`quantity` > 0' : '');
409414

415+
// If we want to select only vouchers that have free shipping as the action
410416
if ($free_shipping_only) {
411-
$sql_part2 .= ' AND free_shipping = 1 AND carrier_restriction = 1';
417+
$sql .= ' AND free_shipping = 1 AND carrier_restriction = 1';
412418
}
413419

420+
// If we want to select only vouchers with "Highlight" option activated
414421
if ($highlight_only) {
415-
$sql_part2 .= ' AND highlight = 1 AND code NOT LIKE "' . pSQL(CartRule::BO_ORDER_CODE_PREFIX) . '%"';
422+
$sql .= ' AND highlight = 1 AND code NOT LIKE "' . pSQL(CartRule::BO_ORDER_CODE_PREFIX) . '%"';
416423
}
417424

418-
$sql = 'SELECT SQL_NO_CACHE ' . $sql_part1 . $sql_where . $sql_part2;
419-
420425
$result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql, true, false);
421426

422427
if (empty($result)) {
@@ -528,7 +533,7 @@ public static function getAllCustomerCartRules(
528533
$query = new DbQuery();
529534
$query->select('cr.*, crl.name');
530535
$query->from('cart_rule', 'cr');
531-
$query->where('cr.id_customer = ' . $customerId . ' OR (cr.`id_customer` = 0 AND (cr.`highlight` = 1 OR cr.`code` = ""))');
536+
$query->where('cr.id_customer = ' . $customerId);
532537
$query->leftJoin('cart_rule_lang', 'crl', 'cr.id_cart_rule = crl.id_cart_rule AND crl.id_lang = ' . (int) Configuration::get('PS_LANG_DEFAULT'));
533538
$query->orderBy('cr.active DESC, cr.id_customer DESC');
534539

classes/Dispatcher.php

+4
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,10 @@ public function hasRoute($route_id, $id_lang = null, $id_shop = null)
853853
$id_shop = (int) Context::getContext()->shop->id;
854854
}
855855

856+
if (!isset($this->routes[$id_shop])) {
857+
$this->loadRoutes($id_shop);
858+
}
859+
856860
return isset($this->routes[$id_shop][$id_lang][$route_id]);
857861
}
858862

classes/Link.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -702,7 +702,7 @@ public function getModuleLink(
702702

703703
// If the module has its own route ... just use it !
704704
if (Dispatcher::getInstance()->hasRoute('module-' . $module . '-' . $controller, $idLang, $idShop)) {
705-
return $this->getPageLink('module-' . $module . '-' . $controller, $ssl, $idLang, $params);
705+
return $this->getPageLink('module-' . $module . '-' . $controller, $ssl, $idLang, $params, false, $idShop);
706706
} else {
707707
return $url . Dispatcher::getInstance()->createUrl('module', $idLang, $params, $this->allow, '', $idShop);
708708
}

classes/Pack.php

+29-16
Original file line numberDiff line numberDiff line change
@@ -255,13 +255,16 @@ public static function isInStock($idProduct, $wantedQuantity = 1, Cart $cart = n
255255
}
256256

257257
/**
258-
* Returns the available quantity of a given pack (this method already have decreased products in cart).
258+
* Returns the available quantity of a given pack.
259+
*
260+
* By default, it returns the TRUE quantity in stock. If you want to, you can pass a $cart parameter
261+
* and the quantity in stock will be reduced by the quantity there is in the cart.
259262
*
260263
* @param int $idProduct Product id
261264
* @param int|null $idProductAttribute Product attribute id (optional)
262-
* @param bool|null $cacheIsPack
263-
* @param CartCore|null $cart
264-
* @param bool|int|null $idCustomization Product customization id (optional)
265+
* @param bool|null $cacheIsPack (unused, you can pass null)
266+
* @param CartCore|null $cart Pass if you want to reduce the quantity by amount in cart
267+
* @param int|null $idCustomization Product customization id (optional)
265268
*
266269
* @return int
267270
*
@@ -284,10 +287,8 @@ public static function getQuantity(
284287
// Initialize
285288
$product = new Product($idProduct, false);
286289
$packQuantity = 0;
287-
$packQuantityInStock = StockAvailable::getQuantityAvailableByProduct(
288-
$idProduct,
289-
$idProductAttribute
290-
);
290+
291+
// We get the pack stock calculation type it has set up
291292
$packStockType = $product->pack_stock_type;
292293
$allPackStockType = [
293294
self::STOCK_TYPE_PACK_ONLY,
@@ -300,20 +301,30 @@ public static function getQuantity(
300301
throw new PrestaShopException('Unknown pack stock type');
301302
}
302303

303-
// If no pack stock or shop default, set it
304-
if (empty($packStockType)
305-
|| $packStockType == self::STOCK_TYPE_DEFAULT
306-
) {
304+
/*
305+
* Now, we have resolved how we will calculate the stock of this pack. It can be one of the following.
306+
*
307+
* STOCK_TYPE_PACK_ONLY - pack 1pcs + product A 10pcs + product B 20pcs = 1pcs
308+
* STOCK_TYPE_PRODUCTS_ONLY - pack 1pcs + product A 10pcs + product B 20pcs = 10 pcs
309+
* STOCK_TYPE_PACK_BOTH - pack 1pcs + product A 10pcs + product B 20pcs = 1 pcs
310+
*/
311+
312+
// If no pack stock or shop default, set it from configuration
313+
if (empty($packStockType) || $packStockType == self::STOCK_TYPE_DEFAULT) {
307314
$packStockType = Configuration::get('PS_PACK_STOCK_TYPE');
308315
}
309316

310-
// Initialize with pack quantity if not only products
317+
// If the quantity of the pack depends only on the pack or both packs and products,
318+
// we need to load the quantity of the pack from stock_available table.
311319
if (in_array($packStockType, [self::STOCK_TYPE_PACK_ONLY, self::STOCK_TYPE_PACK_BOTH])) {
312-
$packQuantity = $packQuantityInStock;
320+
$packQuantity = StockAvailable::getQuantityAvailableByProduct(
321+
$idProduct,
322+
$idProductAttribute
323+
);
313324
}
314325

315-
// Set pack quantity to the minimum quantity of pack, or
316-
// product pack
326+
// If the quantity of the pack depends on the products inside, or both pack and products,
327+
// we need to set the pack quantity to the lowest quantity of products inside.
317328
if (in_array($packStockType, [self::STOCK_TYPE_PACK_BOTH, self::STOCK_TYPE_PRODUCTS_ONLY])) {
318329
$items = array_values(Pack::getItems($idProduct, Configuration::get('PS_LANG_DEFAULT')));
319330

@@ -323,6 +334,7 @@ public static function getQuantity(
323334

324335
// Initialize packQuantity with the first product quantity
325336
// if pack decrement stock type is products only
337+
// @todo This is probably not needed because $packQuantity is always initialized to zero.
326338
if ($index === 0
327339
&& $packStockType == self::STOCK_TYPE_PRODUCTS_ONLY
328340
) {
@@ -331,6 +343,7 @@ public static function getQuantity(
331343
continue;
332344
}
333345

346+
// If the quantity of the individual item is lower than what we currently calculated, it's our new quantity.
334347
if ($nbPackAvailableForItem < $packQuantity) {
335348
$packQuantity = $nbPackAvailableForItem;
336349
}

classes/PrestaShopBackup.php

+7-17
Original file line numberDiff line numberDiff line change
@@ -294,31 +294,21 @@ public function add()
294294
if (!in_array($schema[0]['Table'], $ignoreInsertTable)) {
295295
$data = Db::getInstance()->query('SELECT * FROM `' . $schema[0]['Table'] . '`');
296296
$sizeof = Db::getInstance()->numRows();
297-
$lines = explode("\n", $schema[0]['Create Table']);
298297

299298
if ($data && $sizeof > 0) {
300-
// Export the table data
299+
// First we write the beginning of an insert query
301300
fwrite($fp, 'INSERT INTO `' . $schema[0]['Table'] . "` VALUES\n");
301+
302+
// We start a counter, because we want to separate the queries by batches of 200 lines
302303
$i = 1;
303304
while ($row = Db::getInstance()->nextRow($data)) {
304305
$s = '(';
305306

306-
foreach ($row as $field => $value) {
307-
$tmp = "'" . pSQL($value, true) . "',";
308-
if ($tmp != "'',") {
309-
$s .= $tmp;
307+
foreach ($row as $value) {
308+
if ($value === null) {
309+
$s .= 'NULL,';
310310
} else {
311-
foreach ($lines as $line) {
312-
if (strpos($line, '`' . $field . '`') !== false) {
313-
if (preg_match('/(.*NOT NULL.*)/Ui', $line)) {
314-
$s .= "'',";
315-
} else {
316-
$s .= 'NULL,';
317-
}
318-
319-
break;
320-
}
321-
}
311+
$s .= "'" . pSQL($value, true) . "',";
322312
}
323313
}
324314
$s = rtrim($s, ',');

classes/Product.php

+23-10
Original file line numberDiff line numberDiff line change
@@ -4053,13 +4053,19 @@ public static function displayWtPriceWithCurrency($params, &$smarty)
40534053
}
40544054

40554055
/**
4056-
* Get available product quantities (this method already have decreased products in cart).
4056+
* Gets available product quantity.
4057+
*
4058+
* Method will automatically determine all special conditions and return correct
4059+
* quantity for packs, if needed.
4060+
*
4061+
* By default, it returns the TRUE quantity in stock. If you want to, you can pass a $cart parameter
4062+
* and the quantity in stock will be reduced by the quantity there is in the cart.
40574063
*
40584064
* @param int $idProduct Product identifier
40594065
* @param int|null $idProductAttribute Product attribute id (optional)
4060-
* @param bool|null $cacheIsPack
4061-
* @param CartCore|null $cart
4062-
* @param int|bool|null $idCustomization Product customization id (optional)
4066+
* @param bool|null $cacheIsPack (unused, you can pass null)
4067+
* @param CartCore|null $cart Pass if you want to reduce the quantity by amount in cart
4068+
* @param int|null $idCustomization Product customization id (optional)
40634069
*
40644070
* @return int Available quantities
40654071
*/
@@ -4070,24 +4076,31 @@ public static function getQuantity(
40704076
CartCore $cart = null,
40714077
$idCustomization = null
40724078
) {
4073-
// pack usecase: Pack::getQuantity() returns the pack quantity after cart quantities have been removed from stock
4079+
// If the product is pack, we will handle the logic in another method, because pack stocks can be calculated
4080+
// in multiple ways, depending on the configuration of the pack.
40744081
if (Pack::isPack((int) $idProduct)) {
40754082
return Pack::getQuantity($idProduct, $idProductAttribute, $cacheIsPack, $cart, $idCustomization);
40764083
}
4084+
4085+
// We get the real quantity of the product stock
40774086
$availableQuantity = StockAvailable::getQuantityAvailableByProduct($idProduct, $idProductAttribute);
4078-
$nbProductInCart = 0;
40794087

4080-
// we don't substract products in cart if the cart is already attached to an order, since stock quantity
4081-
// has already been updated, this is only useful when the order has not yet been created
4088+
// Now, if a $cart was passed, we subtract the quantity in cart from the real quantity.
4089+
// We don't substract products in cart if the cart is already attached to an order, since stock quantity
4090+
// has already been updated, this is only useful when the order has not yet been created.
4091+
// @todo This logic should probably be moved somewhere else, this method should not do anything with orders.
4092+
$nbProductInCart = 0;
40824093
if ($cart && empty(Order::getByCartId($cart->id))) {
4094+
/*
4095+
* Now, we get the quantity of the product in cart. This method is clever and in deep_quantity,
4096+
* it will get us the quantity products in all the packs, if there are some in the cart, not just standard products.
4097+
*/
40834098
$cartProduct = $cart->getProductQuantity($idProduct, $idProductAttribute, $idCustomization);
4084-
40854099
if (!empty($cartProduct['deep_quantity'])) {
40864100
$nbProductInCart = $cartProduct['deep_quantity'];
40874101
}
40884102
}
40894103

4090-
// @since 1.5.0
40914104
return $availableQuantity - $nbProductInCart;
40924105
}
40934106

composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@
9292
"prestashop/ps_facetedsearch": "^3.2.1",
9393
"prestashop/ps_faviconnotificationbo": "^2",
9494
"prestashop/ps_featuredproducts": "^2",
95-
"prestashop/ps_googleanalytics": "^4.1",
95+
"prestashop/ps_googleanalytics": "^5",
9696
"prestashop/ps_imageslider": "^3",
9797
"prestashop/ps_languageselector": "^2",
9898
"prestashop/ps_linklist": "^6",

0 commit comments

Comments
 (0)