refactor: Enhance price extraction logic in BOM and export utilities to handle ranges correctly
- Updated `getPriceDisplayFromLinks` and `getPriceDisplayFromLinksAsync` functions to separately extract minimum and maximum prices from price objects, accommodating both single prices and ranges. - Refactored `generateMarkdownOverview` to improve price display by handling min and max values accurately, ensuring proper formatting in markdown outputs. - Added checks to return 'N/A' when no valid prices are found, enhancing robustness of pricing display logic.
This commit is contained in:
@@ -108,18 +108,45 @@ export const getPriceDisplayFromLinks = (item, targetCurrency = null) => {
|
|||||||
const isSingleCurrency = currencies.length === 1;
|
const isSingleCurrency = currencies.length === 1;
|
||||||
|
|
||||||
// Extract numeric values for min/max calculation
|
// Extract numeric values for min/max calculation
|
||||||
const numericPrices = priceObjects.map(p => {
|
// For overall min: use the minimum values from each price (min from ranges, single prices, etc.)
|
||||||
|
// For overall max: use the maximum values from each price (max from ranges, single prices, etc.)
|
||||||
|
const minValues = priceObjects.map(p => {
|
||||||
if (typeof p === 'object' && 'amount' in p) {
|
if (typeof p === 'object' && 'amount' in p) {
|
||||||
const amount = p.amount;
|
const amount = p.amount;
|
||||||
return typeof amount === 'object' && 'min' in amount ? amount.min : (typeof amount === 'number' ? amount : 0);
|
// For ranges, use the min value; for single prices, use the amount
|
||||||
|
if (typeof amount === 'object' && 'min' in amount) {
|
||||||
|
return amount.min;
|
||||||
|
}
|
||||||
|
if (typeof amount === 'number') {
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return extractNumericPrice(p);
|
const extracted = extractNumericPrice(p);
|
||||||
|
return extracted != null ? extracted : 0;
|
||||||
}).filter(p => p != null && p > 0);
|
}).filter(p => p != null && p > 0);
|
||||||
|
|
||||||
if (numericPrices.length === 0) return 'C$0.00';
|
const maxValues = priceObjects.map(p => {
|
||||||
|
if (typeof p === 'object' && 'amount' in p) {
|
||||||
|
const amount = p.amount;
|
||||||
|
// For ranges, use the max value; for single prices, use the amount
|
||||||
|
if (typeof amount === 'object' && 'max' in amount) {
|
||||||
|
return amount.max;
|
||||||
|
}
|
||||||
|
if (typeof amount === 'object' && 'min' in amount) {
|
||||||
|
return amount.min; // If no max, use min (single value range)
|
||||||
|
}
|
||||||
|
if (typeof amount === 'number') {
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const extracted = extractNumericPrice(p);
|
||||||
|
return extracted != null ? extracted : 0;
|
||||||
|
}).filter(p => p != null && p > 0);
|
||||||
|
|
||||||
const minPrice = Math.min(...numericPrices);
|
if (minValues.length === 0 || maxValues.length === 0) return 'C$0.00';
|
||||||
const maxPrice = Math.max(...numericPrices);
|
|
||||||
|
const minPrice = Math.min(...minValues);
|
||||||
|
const maxPrice = Math.max(...maxValues);
|
||||||
|
|
||||||
if (minPrice === maxPrice) {
|
if (minPrice === maxPrice) {
|
||||||
// Single price - format with currency from the first link
|
// Single price - format with currency from the first link
|
||||||
@@ -132,17 +159,36 @@ export const getPriceDisplayFromLinks = (item, targetCurrency = null) => {
|
|||||||
const currencySymbol = currency === 'CAD' ? 'C$' : currency === 'USD' ? '$' : currency === 'EUR' ? '€' : currency === 'GBP' ? '£' : currency;
|
const currencySymbol = currency === 'CAD' ? 'C$' : currency === 'USD' ? '$' : currency === 'EUR' ? '€' : currency === 'GBP' ? '£' : currency;
|
||||||
return `${currencySymbol}${minPrice.toFixed(2)} - ${currencySymbol}${maxPrice.toFixed(2)}`;
|
return `${currencySymbol}${minPrice.toFixed(2)} - ${currencySymbol}${maxPrice.toFixed(2)}`;
|
||||||
} else {
|
} else {
|
||||||
// Multiple currencies - format each with its currency or target currency
|
// Multiple currencies - find the price objects that contain the overall min and max
|
||||||
const minPriceObj = priceObjects.find(p => {
|
const minPriceObj = priceObjects.find(p => {
|
||||||
const amount = p?.amount;
|
if (typeof p === 'object' && 'amount' in p) {
|
||||||
const val = typeof amount === 'object' && 'min' in amount ? amount.min : (typeof amount === 'number' ? amount : 0);
|
const amount = p.amount;
|
||||||
return val === minPrice;
|
if (typeof amount === 'object' && 'min' in amount) {
|
||||||
});
|
return amount.min === minPrice;
|
||||||
|
}
|
||||||
|
if (typeof amount === 'number') {
|
||||||
|
return amount === minPrice;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return extractNumericPrice(p) === minPrice;
|
||||||
|
}) || priceObjects[0]; // Fallback to first if not found
|
||||||
|
|
||||||
const maxPriceObj = priceObjects.find(p => {
|
const maxPriceObj = priceObjects.find(p => {
|
||||||
const amount = p?.amount;
|
if (typeof p === 'object' && 'amount' in p) {
|
||||||
const val = typeof amount === 'object' && 'max' in amount ? amount.max : (typeof amount === 'object' && 'min' in amount ? amount.min : (typeof amount === 'number' ? amount : 0));
|
const amount = p.amount;
|
||||||
return val === maxPrice;
|
if (typeof amount === 'object' && 'max' in amount) {
|
||||||
});
|
return amount.max === maxPrice;
|
||||||
|
}
|
||||||
|
if (typeof amount === 'object' && 'min' in amount) {
|
||||||
|
return amount.min === maxPrice; // Single value range
|
||||||
|
}
|
||||||
|
if (typeof amount === 'number') {
|
||||||
|
return amount === maxPrice;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return extractNumericPrice(p) === maxPrice;
|
||||||
|
}) || priceObjects[priceObjects.length - 1]; // Fallback to last if not found
|
||||||
|
|
||||||
return `${formatPrice(minPriceObj, targetCurrency || 'CAD')} - ${formatPrice(maxPriceObj, targetCurrency || 'CAD')}`;
|
return `${formatPrice(minPriceObj, targetCurrency || 'CAD')} - ${formatPrice(maxPriceObj, targetCurrency || 'CAD')}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -173,18 +219,45 @@ export const getPriceDisplayFromLinksAsync = async (item, targetCurrency = 'CAD'
|
|||||||
if (convertedPrices.length === 0) return 'C$0.00';
|
if (convertedPrices.length === 0) return 'C$0.00';
|
||||||
|
|
||||||
// Extract numeric values for min/max calculation
|
// Extract numeric values for min/max calculation
|
||||||
const numericPrices = convertedPrices.map(p => {
|
// For overall min: use the minimum values from each price (min from ranges, single prices, etc.)
|
||||||
|
// For overall max: use the maximum values from each price (max from ranges, single prices, etc.)
|
||||||
|
const minValues = convertedPrices.map(p => {
|
||||||
if (typeof p === 'object' && 'amount' in p) {
|
if (typeof p === 'object' && 'amount' in p) {
|
||||||
const amount = p.amount;
|
const amount = p.amount;
|
||||||
return typeof amount === 'object' && 'min' in amount ? amount.min : (typeof amount === 'number' ? amount : 0);
|
// For ranges, use the min value; for single prices, use the amount
|
||||||
|
if (typeof amount === 'object' && 'min' in amount) {
|
||||||
|
return amount.min;
|
||||||
|
}
|
||||||
|
if (typeof amount === 'number') {
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return extractNumericPrice(p);
|
const extracted = extractNumericPrice(p);
|
||||||
|
return extracted != null ? extracted : 0;
|
||||||
}).filter(p => p != null && p > 0);
|
}).filter(p => p != null && p > 0);
|
||||||
|
|
||||||
if (numericPrices.length === 0) return 'C$0.00';
|
const maxValues = convertedPrices.map(p => {
|
||||||
|
if (typeof p === 'object' && 'amount' in p) {
|
||||||
|
const amount = p.amount;
|
||||||
|
// For ranges, use the max value; for single prices, use the amount
|
||||||
|
if (typeof amount === 'object' && 'max' in amount) {
|
||||||
|
return amount.max;
|
||||||
|
}
|
||||||
|
if (typeof amount === 'object' && 'min' in amount) {
|
||||||
|
return amount.min; // If no max, use min (single value range)
|
||||||
|
}
|
||||||
|
if (typeof amount === 'number') {
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const extracted = extractNumericPrice(p);
|
||||||
|
return extracted != null ? extracted : 0;
|
||||||
|
}).filter(p => p != null && p > 0);
|
||||||
|
|
||||||
const minPrice = Math.min(...numericPrices);
|
if (minValues.length === 0 || maxValues.length === 0) return 'C$0.00';
|
||||||
const maxPrice = Math.max(...numericPrices);
|
|
||||||
|
const minPrice = Math.min(...minValues);
|
||||||
|
const maxPrice = Math.max(...maxValues);
|
||||||
|
|
||||||
if (minPrice === maxPrice) {
|
if (minPrice === maxPrice) {
|
||||||
return await formatPriceWithConversion(convertedPrices[0], targetCurrency, exchangeRates);
|
return await formatPriceWithConversion(convertedPrices[0], targetCurrency, exchangeRates);
|
||||||
|
|||||||
@@ -12,11 +12,40 @@ export const generateMarkdownOverview = (config, printedParts, hardwareParts, fi
|
|||||||
const getPriceDisplay = (item) => {
|
const getPriceDisplay = (item) => {
|
||||||
if (!item) return 'N/A';
|
if (!item) return 'N/A';
|
||||||
if (item.links && item.links.length > 0) {
|
if (item.links && item.links.length > 0) {
|
||||||
const prices = item.links.map(link => extractNumericPrice(link.price)).filter(p => p != null && p > 0);
|
// Extract min and max values separately to handle price ranges correctly
|
||||||
if (prices.length === 0) return 'N/A';
|
const minPrices = item.links.map(link => {
|
||||||
if (prices.length === 1) return formatPrice(prices[0]);
|
if (link.price && typeof link.price === 'object' && 'amount' in link.price) {
|
||||||
const minPrice = Math.min(...prices);
|
const amount = link.price.amount;
|
||||||
const maxPrice = Math.max(...prices);
|
if (typeof amount === 'object' && 'min' in amount) {
|
||||||
|
return amount.min;
|
||||||
|
}
|
||||||
|
if (typeof amount === 'number') {
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return extractNumericPrice(link.price);
|
||||||
|
}).filter(p => p != null && p > 0);
|
||||||
|
|
||||||
|
const maxPrices = item.links.map(link => {
|
||||||
|
if (link.price && typeof link.price === 'object' && 'amount' in link.price) {
|
||||||
|
const amount = link.price.amount;
|
||||||
|
if (typeof amount === 'object' && 'max' in amount) {
|
||||||
|
return amount.max;
|
||||||
|
}
|
||||||
|
if (typeof amount === 'object' && 'min' in amount) {
|
||||||
|
return amount.min; // Single value range
|
||||||
|
}
|
||||||
|
if (typeof amount === 'number') {
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return extractNumericPrice(link.price);
|
||||||
|
}).filter(p => p != null && p > 0);
|
||||||
|
|
||||||
|
if (minPrices.length === 0 || maxPrices.length === 0) return 'N/A';
|
||||||
|
|
||||||
|
const minPrice = Math.min(...minPrices);
|
||||||
|
const maxPrice = Math.max(...maxPrices);
|
||||||
return minPrice === maxPrice ? formatPrice(minPrice) : `${formatPrice(minPrice)} - ${formatPrice(maxPrice)}`;
|
return minPrice === maxPrice ? formatPrice(minPrice) : `${formatPrice(minPrice)} - ${formatPrice(maxPrice)}`;
|
||||||
}
|
}
|
||||||
return item.price ? formatPrice(item.price) : 'N/A';
|
return item.price ? formatPrice(item.price) : 'N/A';
|
||||||
|
|||||||
Reference in New Issue
Block a user