Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix overlapping text in PersonalDetails component - @jakubmakielkowski (#4024)
- Redirect from checkout to home with a proper store code - @Fifciu
- Added back error notification when user selects invalid configuration - @1070rik (#4033)
- findConfigurableChildAsync - return best match for configurable variant - @gibkigonzo (#4042)

### Changed / Improved
- Optimized `translation.processor` to process only enabled locale CSV files - @pkarw (#3950)
Expand Down
41 changes: 25 additions & 16 deletions core/modules/catalog/helpers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import omit from 'lodash-es/omit'
import remove from 'lodash-es/remove'
import toString from 'lodash-es/toString'
import union from 'lodash-es/union'
import isObject from 'lodash-es/union'
// TODO: Remove this dependency
import { optionLabel } from './optionLabel'
import i18n from '@vue-storefront/i18n'
Expand Down Expand Up @@ -42,8 +43,25 @@ const getVariantWithLowestPrice = (prevVariant, nextVariant) => (
nextVariant.price_incl_tax <= prevVariant.price_incl_tax // prev variant price is higher then next
) ? nextVariant : prevVariant

/**
* Counts how much coniguration match for specific variant
*/
const getConfigurationMatchLevel = (configuration, variant): number => {
if (!variant || !configuration) return 0
const configProperties = Object.keys(omit(configuration, ['price']))
return configProperties
.map(configProperty => {
const filter = configuration[configProperty]
const configurationId = filter && isObject(filter) && filter.id
const variantPropertyId = variant[configProperty]
return (configurationId && variantPropertyId) &&
(toString(configurationId) === toString(variantPropertyId))
})
.filter(Boolean)
.length
}

export function findConfigurableChildAsync ({ product, configuration = null, selectDefaultChildren = false, availabilityCheck = true }) {
const regularProductPrice = product.original_price_incl_tax ? product.original_price_incl_tax : product.price_incl_tax
const selectedVariant = product.configurable_children.reduce((prevVariant, nextVariant) => {
if (availabilityCheck) {
if (nextVariant.stock && !config.products.listOutOfStockProducts) {
Expand All @@ -61,23 +79,14 @@ export function findConfigurableChildAsync ({ product, configuration = null, sel
if (configuration.sku && nextVariant.sku === configuration.sku) { // by sku or first one
return nextVariant
} else {
if (!configuration || (configuration && Object.keys(configuration).length === 0)) { // no configuration - return the first child cheaper than the original price - if found
if (nextVariant.price_incl_tax <= regularProductPrice) {
return getVariantWithLowestPrice(prevVariant, nextVariant)
}
} else {
const matchConfiguration = Object.keys(omit(configuration, ['price'])).every((configProperty) => {
let configurationPropertyFilters = configuration[configProperty] || []
if (!Array.isArray(configurationPropertyFilters)) configurationPropertyFilters = [configurationPropertyFilters]
const configurationIds = configurationPropertyFilters.map(filter => toString(filter.id)).filter(filterId => !!filterId)
if (!configurationIds.length) return true // skip empty
return configurationIds.includes(toString(nextVariant[configProperty]))
})
const prevVariantMatch = getConfigurationMatchLevel(configuration, prevVariant)
const nextVariantMatch = getConfigurationMatchLevel(configuration, nextVariant)

if (matchConfiguration) {
return getVariantWithLowestPrice(prevVariant, nextVariant)
}
if (prevVariantMatch === nextVariantMatch) {
return getVariantWithLowestPrice(prevVariant, nextVariant)
}

return nextVariantMatch > prevVariantMatch ? nextVariant : prevVariant
}
}, undefined)
return selectedVariant
Expand Down