1( function( $, wp, PC ) { 2 3 wp.hooks.addAction( 'PC.fe.init.modal', 'mkl/product_configurator', function( Configurator ) { 4 if ( PC_config.config.hide_outofstock_items ) { 5 Configurator.$el.addClass( 'hide-outofstock-items' ); 6 } 7 } ); 8 9 wp.hooks.addAction( 'PC.fe.start', 'mkl/product_configurator', function( Configurator ) { 10 if ( PC_config.config.hide_outofstock_items ) { 11 Configurator.toolbar.$( 'li.out-of-stock' ).each( function( ind, item ) { 12 $parent = $( item ).closest( 'ul' ); 13 $( item ).remove(); 14 if ( ! $parent.find( 'li' ).length ) { 15 $parent.append( '<li class="out-of-stock--no-more-choice">' + PC_config.lang.outofstock_nomorechoice + '</li>' ); 16 } 17 } ); 18 } 19 } ); 20 21 wp.hooks.addAction( 'PC.fe.start', 'mkl/product_configurator', function( Configurator ) { 22 linked_stock_ready = true; 23 refresh_linked_stock_state(); 24 }, 20000 ); 25 26 /** 27 * Create new PC.fe.currentProductData.linked_products collection, if it wasn't done before 28 */ 29 wp.hooks.addAction( 'PC.fe.setContent.parse.before', 'mkl/product_configurator', function() { 30 linked_stock_ready = false; 31 if ( PC.fe.currentProductData.linked_products_data && ! PC.fe.currentProductData.linked_products ) { 32 PC.fe.currentProductData.linked_products = new Backbone.Collection( PC.fe.currentProductData.linked_products_data ); 33 } 34 } ); 35 36 wp.hooks.addAction( 'PC.fe.reset_configurator', 'mkl/product_configurator', function() { 37 linked_stock_ready = true; 38 refresh_linked_stock_state(); 39 } ); 40 41 const get_choice_qty = function( model ) { 42 const default_min_qty = wp.hooks.applyFilters( 'PC.fe.linked_product.default_min_qty', 1, model ); 43 let qty = parseFloat( model.get( 'linked_product_qty' ) ); 44 if ( Number.isNaN( qty ) || qty <= 0 ) { 45 qty = default_min_qty; 46 } 47 return Math.abs( qty ); 48 }; 49 50 const is_linked_choice = function( model ) { 51 return ( 52 model 53 && 'linked' === model.get( 'manage_stock' ) 54 && model.get( 'linked_product_id' ) 55 && false !== model.get( 'cshow' ) 56 && ! model.get( 'is_group' ) 57 ); 58 }; 59 60 const get_choice_value = function( choice, key ) { 61 if ( choice && 'function' === typeof choice.get ) return choice.get( key ); 62 return choice ? choice[key] : undefined; 63 }; 64 65 const set_choice_value = function( choice, key, value ) { 66 if ( choice && 'function' === typeof choice.set ) { 67 choice.set( key, value ); 68 } else if ( choice ) { 69 choice[key] = value; 70 } 71 }; 72 73 const should_use_linked_product_text = function( choice, field ) { 74 const global_settings = { 75 name: 'link_choice_name_from_product', 76 description: 'link_choice_description_from_product', 77 advanced_description: 'link_advanced_description_from_product', 78 }; 79 const choice_settings = { 80 name: 'linked_product_name_override', 81 description: 'linked_product_description_override', 82 advanced_description: 'linked_product_advanced_description_override', 83 }; 84 85 if ( ! global_settings[field] || ! choice_settings[field] ) return false; 86 if ( 'advanced_description' === field && get_choice_value( choice, 'is_advanced_description_disabled' ) ) return false; 87 88 const mode = get_choice_value( choice, choice_settings[field] ) || 'inherit'; 89 if ( 'use_from_product' === mode ) return true; 90 if ( 'no_override' === mode ) return false; 91 92 return !! PC.fe.config[global_settings[field]]; 93 }; 94 95 const update_linked_product_text = function( choice, product ) { 96 if ( should_use_linked_product_text( choice, 'name' ) ) { 97 const linked_choice_name = product.get( 'extensions' )?.mkl_pc_stock?.linked_choice_name; 98 if ( null !== linked_choice_name && 'undefined' !== typeof linked_choice_name ) { 99 set_choice_value( choice, 'name', linked_choice_name ); 100 } 101 } 102 if ( should_use_linked_product_text( choice, 'description' ) ) { 103 const linked_choice_description = product.get( 'extensions' )?.mkl_pc_stock?.linked_choice_description; 104 if ( null !== linked_choice_description && 'undefined' !== typeof linked_choice_description ) { 105 set_choice_value( choice, 'description', linked_choice_description ); 106 } 107 } 108 if ( should_use_linked_product_text( choice, 'advanced_description' ) ) { 109 const linked_choice_advanced_description = product.get( 'extensions' )?.mkl_pc_stock?.linked_choice_advanced_description; 110 if ( null !== linked_choice_advanced_description && 'undefined' !== typeof linked_choice_advanced_description ) { 111 set_choice_value( choice, 'advanced_description', linked_choice_advanced_description ); 112 } 113 } 114 }; 115 116 let linked_stock_ready = false;
117 118 const get_linked_choices_map = function() { 119 const map = {}; 120 if ( ! PC.fe.layers ) return map; 121 PC.fe.layers.each( function( layer ) { 122 const content = PC.fe.getLayerContent( layer.id ); 123 if ( ! content ) return; 124 content.each( function( choice ) { 125 if ( ! is_linked_choice( choice ) ) return; 126 const linked_product_id = choice.get( 'linked_product_id' ); 127 if ( ! map[linked_product_id] ) { 128 map[linked_product_id] = []; 129 } 130 map[linked_product_id].push( choice ); 131 } ); 132 } ); 133 return map; 134 }; 135 136 const get_linked_stock = function( choice ) { 137 if ( ! choice || ! PC.fe.currentProductData.linked_products ) return null; 138 const linked_product_id = choice.get( 'linked_product_id' ); 139 if ( ! linked_product_id ) return null; 140 const product = PC.fe.currentProductData.linked_products.get( linked_product_id ); 141 if ( ! product ) return null; 142 const maximum = product.get( 'is_in_stock' ) ? parseFloat( product.get( 'add_to_cart' ).maximum ) || 0 : 0; 143 return { 144 product: product, 145 maximum: maximum, 146 }; 147 }; 148 149 const get_required_quantity = function( linked_choices, target_choice = null, include_target = false ) { 150 return linked_choices.reduce( function( required_qty, choice ) { 151 let is_active = !! choice.get( 'active' ); 152 if ( target_choice && choice.cid === target_choice.cid ) { 153 is_active = include_target; 154 } 155 if ( ! is_active ) return required_qty; 156 return required_qty + get_choice_qty( choice ); 157 }, 0 ); 158 }; 159 160 const refresh_linked_stock_state = function() { 161 return; 162 if ( ! linked_stock_ready ) return; 163 if ( ! PC.fe.currentProductData.linked_products ) return; 164 const linked_choices_map = get_linked_choices_map(); 165 Object.values( linked_choices_map ).forEach( function( linked_choices ) { 166 if ( ! linked_choices.length ) return; 167 const stock_data = get_linked_stock( linked_choices[0] ); 168 if ( ! stock_data ) return; 169 let used_stock = 0; 170 171 linked_choices.forEach( function( choice ) { 172 const own_qty = get_choice_qty( choice ); 173 const is_active = !! choice.get( 'active' ); 174 const remaining_for_choice = Math.max( 0, stock_data.maximum - used_stock ); 175 const can_backorder = 'yes' === choice.get( 'wc_backorder' ) || 'notify' === choice.get( 'wc_backorder' ); 176 177 choice.set( 'stock', stock_data.maximum, { silent: true } ); 178 choice.set( 'available', can_backorder || own_qty <= remaining_for_choice ); 179 180 if ( typeof choice.get( 'linked_product_max_qty_raw' ) === 'undefined' ) { 181 const raw_max_qty = choice.get( 'linked_product_max_qty' ); 182 choice.set( 'linked_product_max_qty_raw', raw_max_qty, { silent: true } ); 183 } 184 185 const configured_max = parseFloat( choice.get( 'linked_product_max_qty_raw' ) ); 186 let max_qty = remaining_for_choice; 187 if ( ! Number.isNaN( configured_max ) && configured_max > 0 ) { 188 max_qty = Math.min( max_qty, configured_max ); 189 } 190 choice.set( 'linked_product_max_qty', max_qty ); 191 192 if ( is_active ) { 193 used_stock += own_qty; 194 } 195 } ); 196 } ); 197 }; 198 199 /** 200 * Update product data 201 */ 202 wp.hooks.addAction( 'PC.fe.models.choice.init', 'mkl/product_configurator', function( Model ) { 203 204 var linked_product_id = Model.get( 'linked_product_id'); 205 var stock_management = Model.get( 'manage_stock' ); 206 // Update prices and stock 207 if ( linked_product_id && PC.fe.currentProductData.linked_products ) { 208 var product = PC.fe.currentProductData.linked_products.get( linked_product_id ); 209 if ( product ) { 210 211 const prices = product.get( 'prices' ); 212 213 Model.set( 'linked_product_price', prices.price / 10 ** prices.currency_minor_unit ); 214 215 if ( 'linked' === stock_management ) { 216 update_linked_product_text( Model, product ); 217 218 // Only set prices if we link the extra price, and do not override it 219 if ( 220 // if we Link the extra price 221 PC.fe.config.link_extra_price 222 && !PC.fe.config.extra_price_overrides_product_price 223 && ( 224 !Model.get( 'override_linked_price' ) 225 || ( 226 Model.get( 'override_linked_price' ) 227 && 'replace' !== Model.get( 'override_linked_price_mode' ) 228 ) 229 ) 230 231 ) { 232 233 if ( PC_config.config.tax_settings && 'incl' == PC_config.config.tax_settings.tax_display_mode && ! PC_config.config.tax_settings.prices_include_tax && product.get( 'extensions' ).mkl_pc_stock.price_excl_tax ) { 234 Model.set( 'linked_product_price', product.get( 'extensions' ).mkl_pc_stock.price_excl_tax ); 235 if ( product.get( 'extensions' ).mkl_pc_stock?.regular_price_excl_tax ) Model.set( 'linked_product_regular_price', product.get( 'extensions' ).mkl_pc_stock?.regular_price_excl_tax ); 236 } else if ( PC_config.config.tax_settings && 'excl' === PC_config.config.tax_settings.tax_display_mode && PC_config.config.tax_settings.prices_include_tax && product.get( 'extensions' ).mkl_pc_stock.price_incl_tax ) { 237 Model.set( 'linked_product_price', product.get( 'extensions' ).mkl_pc_stock.price_incl_tax ); 238 if ( product.get( 'extensions' ).mkl_pc_stock?.regular_price_incl_tax ) Model.set( 'linked_product_regular_price', product.get( 'extensions' ).mkl_pc_stock?.regular_price_incl_tax ); 239 } else { 240 Model.set( 'linked_product_price', prices.price / 10 ** prices.currency_minor_unit ); 241 Model.set( 'linked_product_regular_price', prices.regular_price / 10 ** prices.currency_minor_unit ); 242 } 243 244 // Wholesale price 245 if ( product.get( 'extensions' ).mkl_pc_stock.wholesale_price ) { 246 const wholesale_price = product.get( 'extensions' ).mkl_pc_stock.wholesale_price; 247 // If the tax settings are not consistent, we need to reset the wholesale price, as the plugin provides the price with the "tax display mode" applied. 248 if ( PC_config.config.tax_enabled ) { 249 if ( PC_config.config.tax_settings.prices_include_tax ) { 250 var price = wholesale_price.wholesale_price_with_tax; 251 } else { 252 var price = wholesale_price.wholesale_price_with_no_tax; 253 } 254 } else { 255 var price = wholesale_price.wholesale_price; 256 } 257 258 Model.set( 'linked_product_price', price ); 259 } 260 } 261 262 if ( product.get( 'is_in_stock' ) ) { 263 Model.set( 'stock', product.get( 'add_to_cart' ).maximum ); 264 } else { 265 Model.set( 'stock', 0 ); 266 } 267 268 // Maybe change linked_product_max_qty 269 if ( product.get( 'add_to_cart' ).maximum < Model.get( 'linked_product_max_qty' ) ) { 270 Model.set( 'linked_product_max_qty', product.get( 'add_to_cart' ).maximum ); 271 } 272 273 // Maybe change linked_product_default_qty 274 if ( Model.get( 'linked_product_default_qty' ) && product.get( 'add_to_cart' ).maximum < Model.get( 'linked_product_default_qty' ) ) { 275 Model.set( 'linked_product_default_qty', product.get( 'add_to_cart' ).maximum ); 276 } 277 278 if ( product.get( 'is_on_backorder' ) ) { 279 if ( product.get( 'extensions' ) && product.get( 'extensions' ).mkl_pc_stock && product.get( 'extensions' ).mkl_pc_stock.wc_backorder ) { 280 Model.set( 'wc_backorder', product.get( 'extensions' ).mkl_pc_stock.wc_backorder ); 281 } else { 282 Model.set( 'wc_backorder', 'yes' ); 283 } 284 } else { 285 Model.set( 'wc_backorder', 'no' ); 286 } 287 288 // Sale 289 if ( !Model.get( 'override_linked_price' ) && product.get( 'on_sale' ) ) {
290 Model.set( 'on_sale', true ); 291 } 292 } 293 } else { 294 // If product is not found, while stock_management is enabled, set stock to 0 295 if ( 'linked' === stock_management ) { 296 Model.set( 'stock', 0 ); 297 Model.set( 'available', false ); 298 Model.set( 'hide-item', true ); 299 console.warn( 'Product #' + linked_product_id + ' - ' + Model.get( 'linked_product_name' ) + ' was not found in linked product data. The product is linked to Choice ' + Model.get( 'name' ) ); 300 } 301 } 302 } 303 304 var quantity_to_decrease = Model.get( 'linked_product_qty' ) || 1; 305 quantity_to_decrease = ( quantity_to_decrease == null || stock_management != 'linked' ) ? 1 : Math.abs( quantity_to_decrease ); 306 if ( 'none' != stock_management && quantity_to_decrease > Model.get( 'stock' ) ) { 307 if ( 'simple' == stock_management ) { 308 if ( ! Model.get( 'backorder' ) ) { 309 Model.set( 'available', false ); 310 } 311 } else if ( Model.get( 'wc_backorder' ) ) { 312 if ( 'no' == Model.get( 'wc_backorder' ) ) { 313 Model.set( 'available', false ); 314 } 315 } else { 316 Model.set( 'available', false ); 317 } 318 } 319 320 } ); 321 322 wp.hooks.addFilter( 'PC.fe.configurator.choice_data', 'mkl/pc/stock_management_linked_product_text', function( attributes ) { 323 if ( ! attributes || 'linked' !== attributes.manage_stock || ! attributes.linked_product_id || ! PC.fe.currentProductData.linked_products ) return attributes; 324 325 const product = PC.fe.currentProductData.linked_products.get( attributes.linked_product_id ); 326 if ( product ) update_linked_product_text( attributes, product ); 327 328 return attributes; 329 }, 20 ); 330 331 wp.hooks.addAction( 'PC.fe.choice.init', 'mkl/pc/stock_management', function( view ) { 332 view.listenTo( view.model, 'change:linked_product_qty', function( item, value ) { 333 if ( view.$( '.mkl-pc-choice-qty' ).val() != value ) { 334 view.$( '.mkl-pc-choice-qty' ).val( value ); 335 } 336 } ); 337 } ); 338 339 /** 340 * Override price displayed 341 */ 342 wp.hooks.addFilter( 'PC.extra_price_to_display', 'mkl/product_configurator', function( extra_price_do_display, choice ) { 343 if ( 'linked' != choice.get( 'manage_stock' ) || ! PC.fe.config.link_extra_price ) return extra_price_do_display; 344 let qty = 1; 345 const default_min_qty = wp.hooks.applyFilters( 'PC.fe.linked_product.default_min_qty', 1, choice ); 346 347 // Check if we should multiply with the quantity 348 if ( 349 // quantity_multiplies_price is enabled 350 ( ( ! choice.get( 'linked_product_qty_mode' ) || 'multiply' === choice.get( 'linked_product_qty_mode' ) ) && choice.get( 'quantity_multiplies_price' ) ) 351 // OR we do not override prices, so we multiply by default 352 || ( ! PC_config.extra_price_overrides_product_price && choice.get( 'linked_product_qty') && ! choice.get( 'override_linked_price' ) ) 353 ) qty = parseFloat( choice.get( 'linked_product_qty') ) || default_min_qty; 354 355 return parseFloat( extra_price_do_display ) / qty; 356 } ); 357 358 /** 359 * Override a choice's Extra price, depending on the various settings 360 */ 361 wp.hooks.addFilter( 'pc.get_extra_price', 'mkl/product_configurator', function( extra_price, choice, context ) { 362 if ( 'linked' != choice.get( 'manage_stock' ) || ! PC.fe.config.link_extra_price ) return extra_price; 363 364 const forRegularTotal = context && context.forRegularTotal; 365 const linked_regular = choice.get( 'linked_product_regular_price' ); 366 const use_regular_linked = forRegularTotal && 'undefined' != typeof linked_regular && null !== linked_regular && '' !== linked_regular && ! isNaN( parseFloat( linked_regular ) ); 367 368 const default_min_qty = wp.hooks.applyFilters( 'PC.fe.linked_product.default_min_qty', 1, choice ); 369 let qty = default_min_qty; 370 371 // Check if we should multiply with the quantity 372 if ( 373 // quantity_multiplies_price is enabled 374 ( ( ! choice.get( 'linked_product_qty_mode' ) || 'multiply' === choice.get( 'linked_product_qty_mode' ) ) && choice.get( 'quantity_multiplies_price' ) ) 375 // OR we do not override prices, so we multiply by default 376 || ( ! PC_config.extra_price_overrides_product_price && choice.get( 'linked_product_qty') && ! choice.get( 'override_linked_price' ) ) 377 ) qty = parseFloat( choice.get( 'linked_product_qty') ) || default_min_qty; 378 379 380 if ( choice.get( 'override_linked_price' ) ) { 381 if ( 'multiply' == choice.get( 'override_linked_price_mode' ) ) { 382 let multiply_factor = choice.get( 'linked_product_price' ); 383 if ( use_regular_linked ) { 384 multiply_factor = parseFloat( linked_regular ); 385 } 386 extra_price = multiply_factor * extra_price; 387 } 388 } else if ( 'undefined' != typeof choice.get( 'linked_product_price' ) || use_regular_linked ) { 389 extra_price = use_regular_linked ? parseFloat( linked_regular ) : choice.get( 'linked_product_price' ); 390 391 // Tiered pricing checks 392 const linked_product_id = choice.get( 'linked_product_id' ); 393 394 if ( linked_product_id && PC.fe.currentProductData.linked_products ) { 395 const product = PC.fe.currentProductData.linked_products.get( linked_product_id ); 396 397 const quantity = parseFloat( choice.get( 'linked_product_qty') ); 398 399 // Tiered pricing 400 if ( product && product.get( 'extensions' )?.mkl_pc_stock?.price_tiers ) { 401 const product_is_on_sale = product?.get( 'on_sale' ); 402 403 const price_tiers = product.get( 'extensions' ).mkl_pc_stock.price_tiers; 404 const update_price_to_display = ! forRegularTotal && ! ( PC_config.config.relative_price && 'simple' == choice.collection.layer_type ); 405 let tiered_pricing_used = false;
406 const tier = price_tiers.find( ( item ) => quantity >= parseInt( item.start ) ); 407 if ( tier ) { 408 // Percentage or fixed price 409 if ( tier.type.includes( 'percent' ) ) { 410 extra_price = extra_price - ( parseFloat( tier.price ) * parseFloat( extra_price ) / 100 ); 411 } else { 412 extra_price = parseFloat( tier.price || 0 ); 413 } 414 415 if ( update_price_to_display && ( extra_price * qty ) != choice.get( 'extra_price_to_display' ) ) { 416 choice.set( 'extra_price_to_display', extra_price * qty ); 417 } 418 tiered_pricing_used = true; 419 } 420 421 // Maybe update displayed price 422 if ( update_price_to_display && !tiered_pricing_used && ( extra_price * qty ) != choice.get( 'extra_price_to_display' ) ) { 423 choice.set( 'extra_price_to_display', extra_price * qty ); 424 } 425 426 // Set on sale flag 427 if ( ! forRegularTotal ) { 428 if ( tiered_pricing_used && !choice.get( 'on_sale' ) ) { 429 choice.set( 'on_sale', true ) ; 430 } else if ( !tiered_pricing_used && choice.get( 'on_sale' ) && !product_is_on_sale ) { 431 choice.set( 'on_sale', false ) ; 432 } 433 } 434 } 435 } 436 } 437 438 return parseFloat( extra_price ) * qty; 439 } ); 440 441 /** 442 * Hook the data used in the Extra Price view 443 */ 444 wp.hooks.addFilter( 'PC.ExtraPrice.view.data', 'mkl/pc/stock_management', function( data, choice, view ) { 445 if ( PC_config.config.relative_price && 'simple' == choice.collection.layer_type ) return data; 446 if ( choice.get( 'linked_product_regular_price' ) ) { 447 data.formatted_regular_price = PC.utils.formatMoney( Math.abs( pc_maybe_apply_taxes( choice.get( 'linked_product_regular_price' ) ) ) ); 448 } 449 return data; 450 } ); 451 452 wp.hooks.addAction( 'PC.fe.configurator.choice-item.render.after-template', 'mkl/pc/stock_management', function( view ) { 453 454 if ( view.$( '.mkl-pc-choice-qty' ).length ) view.$el.addClass( 'has-qty' ); 455 456 view.$( '.mkl-pc-choice-qty' ).on( 'change', function() { 457 view.model.set( 'linked_product_qty', $( this ).val() ); 458 wp.hooks.doAction( 'PC.fe.linked_product_qty.updated', view ); 459 } ); 460 461 const default_min_qty = wp.hooks.applyFilters( 'PC.fe.linked_product.default_min_qty', 1, view.model ); 462 463 view.$( '.mkl-pc-choice-qty--btn' ).on( 'click', function() { 464 var current_val = parseInt( view.$( '.mkl-pc-choice-qty' ).val() ); 465 if ( $( this ).is( '.mkl-minus' ) ) { 466 var min = view.model.get( 'linked_product_min_qty' ) || default_min_qty; 467 // If the current value is 1, maybe deselect the choice 468 if ( current_val == min ) { 469 view.model.collection.selectChoice( view.model.id, false ); 470 // if ( 'multiple' === view.model.collection.layer_type ) { 471 // view.$( '> .choice-item').trigger( 'mousedown' ); 472 // } 473 return; 474 } 475 view.$( '.mkl-pc-choice-qty' ).val( --current_val ).trigger( 'change' ); 476 } else { 477 if ( view.model.get( 'linked_product_max_qty' ) && current_val == view.model.get( 'linked_product_max_qty' ) ) return; 478 view.$( '.mkl-pc-choice-qty' ).val( ++current_val ).trigger( 'change' ); 479 //.trigger( 'change' ); 480 } 481 } ); 482 } ); 483 484 wp.hooks.addAction( 'PC.fe.configurator.choice-item.render', 'MKL/PC/stock_management', function( view ) { 485 const choice = view.model; 486 if ( 'user_defined' === choice.get( 'linked_product_qty_mode' ) ) { 487 view.$( 'input.mkl-pc-choice-qty' ).trigger( 'change' ); 488 } 489 } ); 490 491 wp.hooks.addFilter( 'PC.fe.choices.add_one', 'MKL/PC/stock_management', function( add_one, model ) { 492 if ( model.get( 'hide-item' ) ) return false; 493 return add_one; 494 } ); 495 496 wp.hooks.addAction( 'PC.fe.setConfig.setItem', 'MKL/PC/stock_management', function( config_item, layer_content ) { 497 var choice = layer_content.get( config_item.choice_id ); 498 if ( ! choice || ! config_item.hasOwnProperty( 'linked_product_qty' ) ) return; 499 500 var qty = choice.set( 'linked_product_qty', config_item.linked_product_qty ); 501 refresh_linked_stock_state(); 502 } ); 503 504 /* 505 Add data for fields attached to normal layers (not form layers) 506 */ 507 wp.hooks.addFilter( 'PC.fe.save_data.parse_choices.added_choice', 'MKL/PC/stock_management', function( parsed_choice, choice_model ) { 508 if ( ! choice_model || ! choice_model.get( 'linked_product_qty' ) ) return parsed_choice; 509 if ( 'user_defined' === choice_model.get( 'linked_product_qty_mode' ) ) { 510 parsed_choice.linked_product_qty = choice_model.get( 'linked_product_qty' ); 511 } 512 return parsed_choice; 513 } ); 514 515 /* 516 Extra price Quantities 517 */ 518 // wp.hooks.addFilter( 'PC.fe.extra_price.item_price', 'MKL/PC/stock_management', function( item_price, choice, layer ) { 519 // if ( ! choice || ! choice.get( 'linked_product_qty' ) ) return item_price; 520 // if ( 'user_defined' !== choice.get( 'linked_product_qty_mode' ) ) { 521 // return item_price * choice.get( 'linked_product_qty' ); 522 // } 523 524 // return item_price; 525 // } ); 526 527 /** 528 * Override a choice's Extra price when calculating the price 529 */ 530 // wp.hooks.addFilter( 'PC.fe.extra_price.item_price', 'mkl/product_configurator', function( item_price, choice, layer ) { 531 // if ( 'linked' != choice.get( 'manage_stock' ) ) return item_price; 532 // if ( PC.fe.config.extra_price_overrides_product_price && ! PC.fe.config.link_extra_price ) return item_price; 533 // // if ( ! choice.get( 'linked_product_qty' ) || 534 // var qty = parseFloat( choice.get( 'linked_product_qty' ) ) || 1; 535 // return parseFloat( item_price ) * qty; 536 // } ); 537 538 wp.hooks.addFilter( 'PC.fe.close_choices_after_selection', 'MKL/PC/stock_management', function( close_choices, choice_model ) { 539 if ( choice_model.get( 'linked_product_qty_mode' ) && 'user_defined' === choice_model.get( 'linked_product_qty_mode' ) ) return false;
540 return close_choices; 541 } ); 542 543 /** 544 * Multiple choice max selection compatibility 545 */ 546 547 /** 548 * Reset quantity on choice deactivation, to prevent quantity miscalculation 549 */ 550 wp.hooks.addAction( 'PC.fe.choice.change', 'MKL/PC/stock_management', function( choice ) { 551 if ( 'multiple' === choice.collection.layer_type ) { 552 /** 553 * Check if the choice is part of a limited layer / group 554 */ 555 var has_max_selection = false; 556 if ( 557 choice.get( 'parent' ) 558 && choice.collection.get( choice.get( 'parent' ) ) 559 && choice.collection.get( choice.get( 'parent' ) ).get( 'max_selection' ) 560 ) has_max_selection = true; 561 562 if ( choice.collection.layer.get( 'max_selection' ) ) has_max_selection = true; 563 564 if ( has_max_selection && choice.get( 'linked_product_qty_mode' ) && 'user_defined' === choice.get( 'linked_product_qty_mode' ) ) { 565 // If the choice was deactivated 566 if ( ! choice.get( 'active' ) ) choice.set( 'linked_product_qty', choice.get( 'linked_product_min_qty' ) || 1 ); 567 } 568 } 569 refresh_linked_stock_state(); 570 } ); 571 572 wp.hooks.addAction( 'PC.fe.linked_product_qty.updated', 'MKL/PC/stock_management', function( { model } ) { 573 if ( model.get( 'linked_product_qty_mode' ) && 'user_defined' === model.get( 'linked_product_qty_mode' ) ) { 574 // If the linked_product_qty changed, check whether it was possible 575 var can_change = wp.hooks.applyFilters( 'PC.choices.canSelectChoice', true, model, model.collection, 'linked_product_quantity' ); 576 if ( ! can_change ) { 577 // Revert field value 578 model.set( 'linked_product_qty', model._previousAttributes.linked_product_qty || 1 ); 579 } 580 581 } 582 refresh_linked_stock_state(); 583 } ); 584 585 wp.hooks.addFilter( 'PC.choices.canSelectChoice', 'MKL/PC/stock_management/shared_stock', function( canSelect, choice, choices, context ) { 586 if ( ! canSelect || ! is_linked_choice( choice ) ) return canSelect; 587 if ( 'choice' === context && ! linked_stock_ready ) return canSelect; 588 const stock_data = get_linked_stock( choice ); 589 if ( ! stock_data ) return canSelect; 590 const can_backorder = 'yes' === choice.get( 'wc_backorder' ) || 'notify' === choice.get( 'wc_backorder' ); 591 if ( can_backorder ) return canSelect; 592 const linked_choices_map = get_linked_choices_map(); 593 const linked_choices = linked_choices_map[choice.get( 'linked_product_id' )] || [ choice ]; 594 return get_required_quantity( linked_choices, choice, true ) <= stock_data.maximum; 595 }, 110 ); 596 597 /** 598 * Revert quantity change if the choice "cannot" be selected (result of PC.choices.canSelectChoice) 599 */ 600 // wp.hooks.addAction( 'PC.fe.form.item.change', 'MKL/PC/stock_management', function( model, event ) { 601 // } ); 602 603 /** 604 * Include the linked_product_qty in the items_selected_count 605 */ 606 wp.hooks.addFilter( 'PC.fe.multiple_choice.item_quantity', 'MKL/PC/stock_management', function( current_count, item, choice ) { 607 if ( !item.get( 'manage_stock' ) || 'linked' !== item.get( 'manage_stock' ) || 'user_defined' !== item.get( 'linked_product_qty_mode' ) ) return current_count; 608 609 let count = 0; 610 const default_min_qty = wp.hooks.applyFilters( 'PC.fe.linked_product.default_min_qty', 1, item ); 611 // Choice is only set when checking if an item is selectable. So we reduce by one to have a "pre-selection" count - if that makes sense! 612 if ( choice === item ) { 613 count += ( parseInt( item.get( 'linked_product_qty' ) ) || default_min_qty ) - 1; 614 } else { 615 count = parseInt( item.get( 'linked_product_qty' ) ) || default_min_qty; 616 } 617 618 return count; 619 }, 100 ); 620 621} ) ( jQuery, window.wp, window.PC );
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.