Skip to content

Commit 8b56993

Browse files
fix: quantity range in pricing matrix (#560)
Improved the price matrix handling by correctly supporting “less than”, range, and “greater than” conditions
1 parent ebfb9b6 commit 8b56993

4 files changed

Lines changed: 81 additions & 25 deletions

File tree

js/price/ppom-price.js

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,17 +1022,49 @@ function ppom_update_get_prices() {
10221022
const apply_as_discount = ppom_pricematrix_discount == 'on' ? true : false;
10231023

10241024
if ( ppom_pricematrix !== undefined ) {
1025-
jQuery.each( JSON.parse( ppom_pricematrix ), function ( range, meta ) {
1025+
const matrixData = JSON.parse(ppom_pricematrix);
1026+
const product_qty = parseInt(ppom_get_order_quantity(), 10);
1027+
1028+
// Pre-process keys ONCE (fix performance + ordering issue)
1029+
const parsedKeys = Object.keys(matrixData).map((range) => {
1030+
if (range.includes('-')) {
1031+
const [start, end] = range.split('-').map(Number);
1032+
return { type: 'range', start, end, key: range };
1033+
} else {
1034+
return { type: 'single', value: Number(range), key: range };
1035+
}
1036+
});
1037+
1038+
parsedKeys.sort((a, b) => {
1039+
const aVal = a.type === 'range' ? a.start : a.value;
1040+
const bVal = b.type === 'range' ? b.start : b.value;
1041+
return aVal - bVal;
1042+
});
1043+
1044+
const firstKey = parsedKeys[0]?.key;
1045+
const lastKey = parsedKeys[parsedKeys.length - 1]?.key;
1046+
1047+
jQuery.each(matrixData, function (range, meta) {
10261048
const option_price = {};
1049+
let isMatch = false;
1050+
1051+
if (range.indexOf('-') !== -1) {
1052+
const [range_from, range_to] = range.split('-').map(Number);
10271053

1028-
const range_break = range.split( '-' );
1029-
const range_from = parseInt( range_break[ 0 ] );
1030-
const range_to = parseInt( range_break[ 1 ] );
1031-
const product_qty = ppom_get_order_quantity();
1054+
if (product_qty >= range_from && product_qty <= range_to) {
1055+
isMatch = true;
1056+
}
1057+
} else {
1058+
const value = Number(range);
10321059

1033-
// console.log(range, meta);
1060+
if (range === firstKey && product_qty <= value) {
1061+
isMatch = true;
1062+
} else if (range === lastKey && product_qty >= value) {
1063+
isMatch = true;
1064+
}
1065+
}
10341066

1035-
if ( product_qty >= range_from && product_qty <= range_to ) {
1067+
if (isMatch) {
10361068
option_price.label = meta.label;
10371069
option_price.price = meta.price;
10381070
option_price.percent = meta.percent;
@@ -1041,11 +1073,13 @@ function ppom_update_get_prices() {
10411073
? 'matrix_discount'
10421074
: 'matrix';
10431075
option_price.data_name = ppom_pricematrix_id;
1044-
option_price.matrix_fixed =
1045-
meta.matrix_fixed == 'on' ? true : false;
1046-
options_price_added.push( option_price );
1076+
option_price.matrix_fixed = meta.matrix_fixed === 'on';
1077+
1078+
options_price_added.push(option_price);
1079+
1080+
return false;
10471081
}
1048-
} );
1082+
});
10491083
}
10501084

10511085
// Variation quantities

src/Support/Helpers.php

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1514,16 +1514,25 @@ public static function extract_matrix_by_quantity( $quantities_field, $product,
15141514
return $matrix;
15151515
}
15161516

1517+
$quantity = intval( $quantity );
15171518
foreach ( $ranges as $range => $data ) {
15181519

1519-
$range_array = explode( '-', $range );
1520-
$range_start = $range_array[0];
1521-
$range_end = $range_array[1];
1520+
if ( strpos( $range, '-' ) !== false ) {
1521+
list( $start, $end ) = array_map( 'intval', explode( '-', $range ) );
1522+
if ( $quantity >= $start && $quantity <= $end ) {
1523+
$matrix = $data;
1524+
break;
1525+
}
1526+
} else {
1527+
$value = intval( $range );
15221528

1523-
$quantity = intval( $quantity );
1524-
if ( $quantity >= $range_start && $quantity <= $range_end ) {
1525-
$matrix = $data;
1526-
break;
1529+
if ( $range === array_key_first( $ranges ) && $quantity <= $value ) {
1530+
$matrix = $data;
1531+
break;
1532+
} elseif ( $range === array_key_last( $ranges ) && $quantity >= $value ) {
1533+
$matrix = $data;
1534+
break;
1535+
}
15271536
}
15281537
}
15291538

src/Validation/Validator.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,11 @@ public static function get_product_limits( $product_id, $variation_id ) {
308308
$first_range = reset( $ranges );
309309
$qty_ranges = explode( '-', $first_range['raw'] );
310310
$min_quantity = $qty_ranges[0];
311+
312+
// If first options is not in range format, set min quantity to 1.
313+
if ( ! isset( $qty_ranges[1] ) ) {
314+
$min_quantity = 1;
315+
}
311316
}
312317
}
313318

@@ -329,7 +334,7 @@ public static function get_product_limits( $product_id, $variation_id ) {
329334

330335
$last_range = end( $ranges );
331336
$qty_ranges = explode( '-', $last_range['raw'] );
332-
$max_quantity = $qty_ranges[1];
337+
$max_quantity = isset( $qty_ranges[1] ) ? $qty_ranges[1] : -1;
333338
}
334339
}
335340

tests/unit/test-checkout-lifecycle.php

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -262,13 +262,19 @@ public function testWooCommerceGetCartItemFromSessionRecalculatesMatrixPriceWhen
262262
'price_matrix',
263263
array(
264264
array(
265-
'option' => '1-2',
265+
'option' => '5',
266266
'price' => '12',
267267
'label' => 'Low quantity',
268268
'id' => 'low_qty',
269269
),
270270
array(
271-
'option' => '3-5',
271+
'option' => '5-10',
272+
'price' => '10',
273+
'label' => 'Range quantity',
274+
'id' => 'range_qty',
275+
),
276+
array(
277+
'option' => '11',
272278
'price' => '8',
273279
'label' => 'High quantity',
274280
'id' => 'high_qty',
@@ -279,11 +285,13 @@ public function testWooCommerceGetCartItemFromSessionRecalculatesMatrixPriceWhen
279285
$product->get_id()
280286
);
281287

282-
$initial = $this->restore_cart_item_from_session( wc_get_product( $product->get_id() ), array(), 1 );
283-
$updated = $this->restore_cart_item_from_session( wc_get_product( $product->get_id() ), array(), 3 );
288+
$low_quantity = $this->restore_cart_item_from_session( wc_get_product( $product->get_id() ), array(), 3 );
289+
$range_quantity = $this->restore_cart_item_from_session( wc_get_product( $product->get_id() ), array(), 7 );
290+
$high_quantity = $this->restore_cart_item_from_session( wc_get_product( $product->get_id() ), array(), 15 );
284291

285-
$this->assertSame( 12.0, (float) $initial['data']->get_price() );
286-
$this->assertSame( 8.0, (float) $updated['data']->get_price() );
292+
$this->assertSame( 12.0, (float) $low_quantity['data']->get_price() );
293+
$this->assertSame( 10.0, (float) $range_quantity['data']->get_price() );
294+
$this->assertSame( 8.0, (float) $high_quantity['data']->get_price() );
287295
}
288296

289297
/**

0 commit comments

Comments
 (0)