medusa-product-helper 0.0.16 → 0.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.medusa/server/src/admin/index.js +59 -117
- package/.medusa/server/src/admin/index.mjs +59 -117
- package/.medusa/server/src/api/store/product-helper/products/route.js +41 -5
- package/.medusa/server/src/api/store/product-helper/products/validators.js +2 -1
- package/.medusa/server/src/providers/filter-providers/availability-provider.js +53 -67
- package/.medusa/server/src/providers/filter-providers/base-filter-provider.js +1 -19
- package/.medusa/server/src/providers/filter-providers/base-product-provider.js +37 -100
- package/.medusa/server/src/providers/filter-providers/category-provider.js +15 -34
- package/.medusa/server/src/providers/filter-providers/collection-provider.js +15 -32
- package/.medusa/server/src/providers/filter-providers/index.js +13 -49
- package/.medusa/server/src/providers/filter-providers/metadata-provider.js +38 -57
- package/.medusa/server/src/providers/filter-providers/price-range-provider.js +66 -79
- package/.medusa/server/src/providers/filter-providers/promotion-provider.js +106 -169
- package/.medusa/server/src/providers/filter-providers/promotion-window-provider.js +53 -93
- package/.medusa/server/src/providers/filter-providers/rating-provider.js +47 -70
- package/.medusa/server/src/services/dynamic-filter-service.js +455 -744
- package/.medusa/server/src/services/filter-provider-loader.js +91 -139
- package/.medusa/server/src/services/filter-provider-registry.js +8 -107
- package/.medusa/server/src/services/product-filter-service.js +127 -174
- package/.medusa/server/src/shared/product-metadata/utils.js +66 -116
- package/.medusa/server/src/utils/query-builders/product-filters.js +89 -111
- package/.medusa/server/src/utils/query-parser.js +24 -76
- package/.medusa/server/src/workflows/add-to-wishlist.js +12 -26
- package/.medusa/server/src/workflows/get-wishlist.js +53 -51
- package/.medusa/server/src/workflows/remove-from-wishlist.js +3 -8
- package/package.json +1 -1
|
@@ -3,812 +3,523 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.DynamicFilterService = void 0;
|
|
4
4
|
const utils_1 = require("@medusajs/framework/utils");
|
|
5
5
|
const filter_provider_registry_1 = require("./filter-provider-registry");
|
|
6
|
-
/**
|
|
7
|
-
* Service that orchestrates filter application using filter providers.
|
|
8
|
-
*
|
|
9
|
-
* This service coordinates between filter providers and Medusa's RemoteQuery
|
|
10
|
-
* to build and execute product queries with dynamic filters. It handles:
|
|
11
|
-
* - Resolving providers for filter identifiers
|
|
12
|
-
* - Validating filter values
|
|
13
|
-
* - Applying filters to build query filters
|
|
14
|
-
* - Executing queries with pagination and sorting
|
|
15
|
-
*
|
|
16
|
-
* @example
|
|
17
|
-
* ```ts
|
|
18
|
-
* const service = new DynamicFilterService(container)
|
|
19
|
-
* const result = await service.applyFilters({
|
|
20
|
-
* filterParams: {
|
|
21
|
-
* category_id: ["cat_123"],
|
|
22
|
-
* price_range: { min: 10, max: 100 },
|
|
23
|
-
* },
|
|
24
|
-
* options: pluginOptions,
|
|
25
|
-
* pagination: { limit: 20, offset: 0 },
|
|
26
|
-
* })
|
|
27
|
-
* ```
|
|
28
|
-
*/
|
|
29
6
|
class DynamicFilterService {
|
|
30
7
|
constructor(container) {
|
|
31
|
-
|
|
32
|
-
try {
|
|
33
|
-
this.registry = container.resolve("filterProviderRegistry");
|
|
34
|
-
}
|
|
35
|
-
catch {
|
|
36
|
-
// Registry not registered, create new one and register built-in providers
|
|
37
|
-
// This allows the service to work even if registry wasn't pre-registered
|
|
38
|
-
this.registry = new filter_provider_registry_1.FilterProviderRegistry();
|
|
39
|
-
// Auto-register built-in providers
|
|
40
|
-
try {
|
|
41
|
-
const { registerBuiltInProviders } = require("../providers/filter-providers");
|
|
42
|
-
registerBuiltInProviders(this.registry);
|
|
43
|
-
}
|
|
44
|
-
catch (error) {
|
|
45
|
-
// If registration fails, log but continue
|
|
46
|
-
console.warn("[DynamicFilterService] Failed to auto-register built-in providers:", error instanceof Error ? error.message : String(error));
|
|
47
|
-
}
|
|
48
|
-
}
|
|
8
|
+
this.registry = this.resolveRegistry(container);
|
|
49
9
|
this.query = container.resolve(utils_1.ContainerRegistrationKeys.QUERY);
|
|
50
10
|
}
|
|
51
|
-
/**
|
|
52
|
-
* Get the filter provider registry.
|
|
53
|
-
* Useful for registering providers programmatically.
|
|
54
|
-
*/
|
|
55
11
|
getRegistry() {
|
|
56
12
|
return this.registry;
|
|
57
13
|
}
|
|
58
|
-
/**
|
|
59
|
-
* Apply filters to a product query and return results.
|
|
60
|
-
*
|
|
61
|
-
* This method:
|
|
62
|
-
* 1. Iterates through filter parameters
|
|
63
|
-
* 2. Resolves providers for each filter identifier
|
|
64
|
-
* 3. Validates filter values (if provider has validate method)
|
|
65
|
-
* 4. Applies filters to build the query filters object
|
|
66
|
-
* 5. Executes the query with pagination and sorting
|
|
67
|
-
* 6. Returns products and count
|
|
68
|
-
*
|
|
69
|
-
* @param options - Options for applying filters
|
|
70
|
-
* @returns Products and count matching the filters
|
|
71
|
-
* @throws Error if provider validation fails or provider application fails (fail-fast)
|
|
72
|
-
*
|
|
73
|
-
* @example
|
|
74
|
-
* ```ts
|
|
75
|
-
* const result = await service.applyFilters({
|
|
76
|
-
* filterParams: {
|
|
77
|
-
* category_id: ["cat_123", "cat_456"],
|
|
78
|
-
* price_range: { min: 10, max: 100 },
|
|
79
|
-
* },
|
|
80
|
-
* options: pluginOptions,
|
|
81
|
-
* pagination: { limit: 20, offset: 0 },
|
|
82
|
-
* projection: { fields: ["id", "title", "handle"] },
|
|
83
|
-
* })
|
|
84
|
-
* ```
|
|
85
|
-
*/
|
|
86
14
|
async applyFilters(options) {
|
|
87
|
-
const { filterParams, options: pluginOptions, pagination, projection, context = {}
|
|
88
|
-
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
15
|
+
const { filterParams, options: pluginOptions, pagination, projection, context = {} } = options;
|
|
16
|
+
const filterContext = { ...context, options: pluginOptions };
|
|
17
|
+
const { queryFilters, priceRangeFilter, promotionFilter } = await this.processFilters(filterParams, filterContext);
|
|
18
|
+
const fields = this.buildFields(projection?.fields);
|
|
19
|
+
const queryContext = this.buildQueryContext(context);
|
|
20
|
+
const queryOptions = this.buildQueryOptions(queryFilters, fields, pagination, queryContext);
|
|
21
|
+
const result = await this.query.graph(queryOptions);
|
|
22
|
+
const { data: productsRaw = [], metadata } = result;
|
|
23
|
+
let products = this.normalizeProducts(productsRaw);
|
|
24
|
+
products = await this.applyPostQueryFilters(products, priceRangeFilter, promotionFilter);
|
|
25
|
+
// Count should reflect filtered products, not initial query count
|
|
26
|
+
// If post-query filters were applied, use filtered products length
|
|
27
|
+
// Otherwise, use metadata count or products length
|
|
28
|
+
const hasPostQueryFilters = priceRangeFilter || promotionFilter;
|
|
29
|
+
const count = hasPostQueryFilters
|
|
30
|
+
? products.length
|
|
31
|
+
: await this.getCount(queryFilters, metadata, products.length);
|
|
32
|
+
return {
|
|
33
|
+
products,
|
|
34
|
+
count,
|
|
35
|
+
metadata: {
|
|
36
|
+
count,
|
|
37
|
+
skip: pagination?.offset,
|
|
38
|
+
take: pagination?.limit || (hasPostQueryFilters ? undefined : 20),
|
|
39
|
+
},
|
|
92
40
|
};
|
|
93
|
-
|
|
41
|
+
}
|
|
42
|
+
resolveRegistry(container) {
|
|
43
|
+
try {
|
|
44
|
+
return container.resolve("filterProviderRegistry");
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
const registry = new filter_provider_registry_1.FilterProviderRegistry();
|
|
48
|
+
this.autoRegisterBuiltInProviders(registry);
|
|
49
|
+
return registry;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
autoRegisterBuiltInProviders(registry) {
|
|
53
|
+
try {
|
|
54
|
+
const { registerBuiltInProviders } = require("../providers/filter-providers");
|
|
55
|
+
registerBuiltInProviders(registry);
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
console.warn("[DynamicFilterService] Failed to auto-register built-in providers:", error);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async processFilters(filterParams, filterContext) {
|
|
94
62
|
let queryFilters = {};
|
|
95
63
|
let priceRangeFilter;
|
|
96
64
|
let promotionFilter;
|
|
97
|
-
// Apply each filter using its provider
|
|
98
65
|
for (const [identifier, value] of Object.entries(filterParams)) {
|
|
99
|
-
|
|
100
|
-
if (value === undefined || value === null) {
|
|
66
|
+
if (value == null)
|
|
101
67
|
continue;
|
|
102
|
-
}
|
|
103
68
|
const provider = this.registry.get(identifier);
|
|
104
69
|
if (!provider) {
|
|
105
|
-
|
|
106
|
-
// This enables custom providers to be added without breaking existing code
|
|
107
|
-
console.warn(`[DynamicFilterService] No filter provider found for identifier: "${identifier}". ` +
|
|
108
|
-
`Filter will be ignored. Available providers: ${this.registry.getIdentifiers().join(", ")}`);
|
|
70
|
+
console.warn(`[DynamicFilterService] No filter provider found for: "${identifier}"`);
|
|
109
71
|
continue;
|
|
110
72
|
}
|
|
111
73
|
try {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
.join(", ");
|
|
120
|
-
throw new Error(`Filter validation failed for "${identifier}": ${errors}`);
|
|
121
|
-
}
|
|
122
|
-
// If validate() throws, it will be caught below
|
|
123
|
-
}
|
|
124
|
-
// Apply filter
|
|
125
|
-
const result = provider.apply(queryFilters, value, filterContext);
|
|
126
|
-
queryFilters = await Promise.resolve(result);
|
|
127
|
-
// Extract price range filter for post-query filtering
|
|
128
|
-
// Price filtering requires post-query filtering because Medusa's query API
|
|
129
|
-
// doesn't support price range filtering directly
|
|
130
|
-
if (queryFilters.__price_range_filter__) {
|
|
131
|
-
priceRangeFilter = queryFilters.__price_range_filter__;
|
|
132
|
-
// Remove from queryFilters so it doesn't get passed to the query
|
|
133
|
-
delete queryFilters.__price_range_filter__;
|
|
134
|
-
}
|
|
135
|
-
// Extract promotion filter for post-query filtering
|
|
136
|
-
// Promotion filtering requires querying Medusa's promotion module and
|
|
137
|
-
// matching products via promotion rules/targets, which can't be done directly
|
|
138
|
-
if (queryFilters.__promotion_filter__) {
|
|
139
|
-
promotionFilter = queryFilters.__promotion_filter__;
|
|
140
|
-
// Remove from queryFilters so it doesn't get passed to the query
|
|
141
|
-
delete queryFilters.__promotion_filter__;
|
|
142
|
-
}
|
|
74
|
+
this.validateWithProvider(provider, value);
|
|
75
|
+
const result = await Promise.resolve(provider.apply(queryFilters, value, filterContext));
|
|
76
|
+
queryFilters = result;
|
|
77
|
+
priceRangeFilter = queryFilters.__price_range_filter__;
|
|
78
|
+
promotionFilter = queryFilters.__promotion_filter__;
|
|
79
|
+
delete queryFilters.__price_range_filter__;
|
|
80
|
+
delete queryFilters.__promotion_filter__;
|
|
143
81
|
}
|
|
144
82
|
catch (error) {
|
|
145
|
-
|
|
146
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
147
|
-
throw new Error(`Error applying filter "${identifier}": ${errorMessage}`);
|
|
83
|
+
throw new Error(`Error applying filter "${identifier}": ${error}`);
|
|
148
84
|
}
|
|
149
85
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
// Medusa's RemoteQuery may not automatically include nested relations with "*"
|
|
159
|
-
if (fields.includes("*")) {
|
|
160
|
-
// When using "*", explicitly add relations to ensure they're included
|
|
161
|
-
// This ensures variants, options, images, collection, and type are returned
|
|
162
|
-
fields = [
|
|
163
|
-
"*",
|
|
164
|
-
"variants.*",
|
|
165
|
-
"variants.prices.*",
|
|
166
|
-
"options.*",
|
|
167
|
-
"options.values.*",
|
|
168
|
-
"images.*",
|
|
169
|
-
"collection.*",
|
|
170
|
-
"type.*",
|
|
171
|
-
];
|
|
172
|
-
}
|
|
173
|
-
else {
|
|
174
|
-
// If specific fields are requested, ensure essential relations are included
|
|
175
|
-
const hasVariants = fields.some(f => f.startsWith("variants"));
|
|
176
|
-
const hasOptions = fields.some(f => f.startsWith("options"));
|
|
177
|
-
const hasImages = fields.some(f => f.startsWith("images"));
|
|
178
|
-
const hasCollection = fields.includes("collection") || fields.some(f => f.startsWith("collection"));
|
|
179
|
-
const hasType = fields.includes("type") || fields.some(f => f.startsWith("type"));
|
|
180
|
-
// Add missing essential relations
|
|
181
|
-
if (!hasVariants) {
|
|
182
|
-
fields.push("variants.*", "variants.prices.*");
|
|
183
|
-
}
|
|
184
|
-
if (!hasOptions) {
|
|
185
|
-
fields.push("options.*", "options.values.*");
|
|
186
|
-
}
|
|
187
|
-
if (!hasImages)
|
|
188
|
-
fields.push("images.*");
|
|
189
|
-
if (!hasCollection)
|
|
190
|
-
fields.push("collection.*");
|
|
191
|
-
if (!hasType)
|
|
192
|
-
fields.push("type.*");
|
|
193
|
-
}
|
|
194
|
-
// Build query context for pricing (similar to Medusa's official route)
|
|
195
|
-
const queryContext = {};
|
|
196
|
-
// Add pricing context if available
|
|
197
|
-
if (context && typeof context === "object" && "pricingContext" in context) {
|
|
198
|
-
const pricingContext = context.pricingContext;
|
|
199
|
-
if (pricingContext) {
|
|
200
|
-
queryContext.variants = {
|
|
201
|
-
calculated_price: (0, utils_1.QueryContext)(pricingContext),
|
|
202
|
-
};
|
|
86
|
+
return { queryFilters, priceRangeFilter, promotionFilter };
|
|
87
|
+
}
|
|
88
|
+
validateWithProvider(provider, value) {
|
|
89
|
+
if (provider.validate) {
|
|
90
|
+
const validationResult = provider.validate(value);
|
|
91
|
+
if (Array.isArray(validationResult)) {
|
|
92
|
+
const errors = validationResult.map(err => `${err.path ? `${err.path}: ` : ""}${err.message}`).join(", ");
|
|
93
|
+
throw new Error(errors);
|
|
203
94
|
}
|
|
204
95
|
}
|
|
205
|
-
|
|
96
|
+
}
|
|
97
|
+
buildFields(requestedFields) {
|
|
98
|
+
const essentialRelations = [
|
|
99
|
+
"variants.*", "variants.prices.*",
|
|
100
|
+
"options.*", "options.values.*",
|
|
101
|
+
"images.*", "collection.*", "type.*"
|
|
102
|
+
];
|
|
103
|
+
if (!requestedFields?.length || requestedFields.includes("*")) {
|
|
104
|
+
return ["*", ...essentialRelations];
|
|
105
|
+
}
|
|
106
|
+
const fields = [...requestedFields];
|
|
107
|
+
const has = (prefix) => fields.some(f => f.startsWith(prefix));
|
|
108
|
+
if (!has("variants"))
|
|
109
|
+
fields.push("variants.*", "variants.prices.*");
|
|
110
|
+
if (!has("options"))
|
|
111
|
+
fields.push("options.*", "options.values.*");
|
|
112
|
+
if (!has("images"))
|
|
113
|
+
fields.push("images.*");
|
|
114
|
+
if (!has("collection"))
|
|
115
|
+
fields.push("collection.*");
|
|
116
|
+
if (!has("type"))
|
|
117
|
+
fields.push("type.*");
|
|
118
|
+
return fields;
|
|
119
|
+
}
|
|
120
|
+
buildQueryContext(context) {
|
|
121
|
+
if (context?.pricingContext) {
|
|
122
|
+
return { variants: { calculated_price: context.pricingContext } };
|
|
123
|
+
}
|
|
124
|
+
return {};
|
|
125
|
+
}
|
|
126
|
+
buildQueryOptions(filters, fields, pagination, queryContext) {
|
|
127
|
+
const options = {
|
|
206
128
|
entity: "product",
|
|
207
129
|
fields,
|
|
208
|
-
...(Object.keys(
|
|
209
|
-
...(pagination && {
|
|
210
|
-
pagination: {
|
|
211
|
-
...(pagination.limit !== undefined && { take: pagination.limit }),
|
|
212
|
-
...(pagination.offset !== undefined && { skip: pagination.offset }),
|
|
213
|
-
},
|
|
214
|
-
}),
|
|
215
|
-
...(Object.keys(queryContext).length > 0 && { context: queryContext }),
|
|
130
|
+
...(Object.keys(filters).length > 0 && { filters }),
|
|
216
131
|
};
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
// Ensure products is always an array and filter out null/undefined
|
|
231
|
-
let products = [];
|
|
232
|
-
if (Array.isArray(productsRaw)) {
|
|
233
|
-
products = productsRaw.filter((p) => p !== null && p !== undefined);
|
|
132
|
+
if (pagination) {
|
|
133
|
+
options.pagination = {};
|
|
134
|
+
// Ensure default limit if limit is 0 or undefined
|
|
135
|
+
if (pagination.limit !== undefined && pagination.limit > 0) {
|
|
136
|
+
options.pagination.take = pagination.limit;
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
// Default limit when limit is 0 or undefined
|
|
140
|
+
options.pagination.take = 20;
|
|
141
|
+
}
|
|
142
|
+
if (pagination.offset !== undefined) {
|
|
143
|
+
options.pagination.skip = pagination.offset;
|
|
144
|
+
}
|
|
234
145
|
}
|
|
235
146
|
else {
|
|
236
|
-
//
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
147
|
+
// If no pagination provided, set default
|
|
148
|
+
options.pagination = {
|
|
149
|
+
take: 20,
|
|
150
|
+
skip: 0
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
if (queryContext && Object.keys(queryContext).length > 0) {
|
|
154
|
+
options.context = queryContext;
|
|
155
|
+
}
|
|
156
|
+
return options;
|
|
157
|
+
}
|
|
158
|
+
normalizeProducts(productsRaw) {
|
|
159
|
+
if (Array.isArray(productsRaw)) {
|
|
160
|
+
return productsRaw.filter(p => p != null);
|
|
161
|
+
}
|
|
162
|
+
console.warn("[DynamicFilterService] Unexpected data structure from query.graph()");
|
|
163
|
+
return [];
|
|
164
|
+
}
|
|
165
|
+
async applyPostQueryFilters(products, priceRangeFilter, promotionFilter) {
|
|
166
|
+
let filteredProducts = products;
|
|
167
|
+
if (priceRangeFilter && filteredProducts.length > 0) {
|
|
168
|
+
filteredProducts = this.filterByPriceRange(filteredProducts, priceRangeFilter);
|
|
169
|
+
}
|
|
170
|
+
if (promotionFilter && filteredProducts.length > 0) {
|
|
171
|
+
filteredProducts = await this.filterByPromotion(filteredProducts, promotionFilter);
|
|
172
|
+
}
|
|
173
|
+
return filteredProducts;
|
|
174
|
+
}
|
|
175
|
+
filterByPriceRange(products, priceRangeFilter) {
|
|
176
|
+
return products.filter(product => {
|
|
177
|
+
if (!product.variants?.length)
|
|
178
|
+
return false;
|
|
179
|
+
return product.variants.some((variant) => {
|
|
180
|
+
const priceInfo = this.getPriceInfo(variant);
|
|
181
|
+
if (!priceInfo.price)
|
|
182
|
+
return false;
|
|
183
|
+
if (priceRangeFilter.currency_code && priceInfo.currency !== priceRangeFilter.currency_code) {
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
const { min, max } = priceRangeFilter;
|
|
187
|
+
if (min !== undefined && priceInfo.price < min)
|
|
188
|
+
return false;
|
|
189
|
+
if (max !== undefined && priceInfo.price > max)
|
|
190
|
+
return false;
|
|
191
|
+
return true;
|
|
242
192
|
});
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
getPriceInfo(variant) {
|
|
196
|
+
if (variant.calculated_price?.calculated_amount !== undefined) {
|
|
197
|
+
return {
|
|
198
|
+
price: variant.calculated_price.calculated_amount,
|
|
199
|
+
currency: variant.calculated_price.currency_code
|
|
200
|
+
};
|
|
243
201
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
202
|
+
if (variant.prices?.[0]) {
|
|
203
|
+
const price = variant.prices[0];
|
|
204
|
+
return { price: price.amount, currency: price.currency_code };
|
|
205
|
+
}
|
|
206
|
+
return {};
|
|
207
|
+
}
|
|
208
|
+
async filterByPromotion(products, promotionFilter) {
|
|
209
|
+
try {
|
|
210
|
+
const promotions = await this.fetchPromotions(promotionFilter);
|
|
211
|
+
// Debug logging
|
|
212
|
+
console.log(`[DynamicFilterService] Found ${promotions.length} promotions matching filter`);
|
|
213
|
+
if (promotions.length === 0) {
|
|
214
|
+
console.warn("[DynamicFilterService] No promotions found - returning empty array");
|
|
215
|
+
return [];
|
|
216
|
+
}
|
|
217
|
+
const productPromotionData = await this.extractProductPromotionData(promotions);
|
|
218
|
+
// Debug logging
|
|
219
|
+
console.log(`[DynamicFilterService] Extracted ${productPromotionData.productIds.size} unique product IDs from promotions`);
|
|
220
|
+
console.log(`[DynamicFilterService] Found discounts for ${productPromotionData.discounts.size} products`);
|
|
221
|
+
console.log(`[DynamicFilterService] Has universal promotions (no rules): ${productPromotionData.hasUniversalPromotions}`);
|
|
222
|
+
// If we have universal promotions (no rules = applies to all products)
|
|
223
|
+
// or if we have product IDs, filter accordingly
|
|
224
|
+
const hasProductIds = productPromotionData.productIds.size > 0;
|
|
225
|
+
const hasUniversalPromotions = productPromotionData.hasUniversalPromotions;
|
|
226
|
+
if (!hasProductIds && !hasUniversalPromotions) {
|
|
227
|
+
console.warn("[DynamicFilterService] No product IDs found and no universal promotions - returning empty array");
|
|
228
|
+
return [];
|
|
229
|
+
}
|
|
230
|
+
const filtered = products.filter(product => {
|
|
231
|
+
const productId = product?.id;
|
|
232
|
+
if (!productId)
|
|
233
|
+
return false;
|
|
234
|
+
// If promotion has no rules (universal), it applies to all products
|
|
235
|
+
// Otherwise, check if product is in the promotion's product list
|
|
236
|
+
if (hasProductIds && !productPromotionData.productIds.has(productId)) {
|
|
251
237
|
return false;
|
|
252
238
|
}
|
|
253
|
-
//
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
239
|
+
// Get discount for this product (from specific promotion or universal promotion)
|
|
240
|
+
let discount = productPromotionData.discounts.get(productId) || 0;
|
|
241
|
+
// If no specific discount found but we have universal promotions, use the universal discount
|
|
242
|
+
if (discount === 0 && hasUniversalPromotions) {
|
|
243
|
+
// Use the discount from the first universal promotion
|
|
244
|
+
discount = productPromotionData.universalDiscount || 0;
|
|
245
|
+
}
|
|
246
|
+
const meetsCriteria = this.meetsDiscountCriteria(discount, promotionFilter);
|
|
247
|
+
if (!meetsCriteria) {
|
|
248
|
+
console.log(`[DynamicFilterService] Product ${productId} discount ${discount}% does not meet criteria (min: ${promotionFilter.min_discount_percentage}, max: ${promotionFilter.max_discount_percentage})`);
|
|
249
|
+
}
|
|
250
|
+
return meetsCriteria;
|
|
251
|
+
});
|
|
252
|
+
console.log(`[DynamicFilterService] Filtered ${products.length} products down to ${filtered.length} matching promotion criteria`);
|
|
253
|
+
return filtered;
|
|
254
|
+
}
|
|
255
|
+
catch (error) {
|
|
256
|
+
console.warn("[DynamicFilterService] Error filtering by promotions:", error);
|
|
257
|
+
return products;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
async fetchPromotions(promotionFilter) {
|
|
261
|
+
const queryOptions = {
|
|
262
|
+
entity: "promotion",
|
|
263
|
+
fields: [
|
|
264
|
+
"id", "code", "type", "application_method.*", "campaign.*",
|
|
265
|
+
"rules.*", "rules.values.*", "starts_at", "ends_at", "status", "metadata"
|
|
266
|
+
],
|
|
267
|
+
};
|
|
268
|
+
const filters = {};
|
|
269
|
+
// Status filter (default to active if not specified)
|
|
270
|
+
if (promotionFilter.status) {
|
|
271
|
+
filters.status = promotionFilter.status;
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
// Default to active promotions
|
|
275
|
+
filters.status = "active";
|
|
276
|
+
}
|
|
277
|
+
if (promotionFilter.promotion_type) {
|
|
278
|
+
filters.type = promotionFilter.promotion_type;
|
|
279
|
+
}
|
|
280
|
+
if (Object.keys(filters).length > 0) {
|
|
281
|
+
queryOptions.filters = filters;
|
|
282
|
+
}
|
|
283
|
+
// Fetch all promotions matching status/type filters
|
|
284
|
+
// Date filtering will be done in code since Medusa query API
|
|
285
|
+
// may not support complex date range queries
|
|
286
|
+
const result = await this.query.graph(queryOptions);
|
|
287
|
+
let promotions = Array.isArray(result.data) ? result.data : [];
|
|
288
|
+
// Filter by date ranges in code
|
|
289
|
+
const now = new Date();
|
|
290
|
+
promotions = promotions.filter((promo) => {
|
|
291
|
+
// Check starts_at
|
|
292
|
+
if (promo.starts_at) {
|
|
293
|
+
const startsAt = new Date(promo.starts_at);
|
|
294
|
+
if (promotionFilter.starts_at) {
|
|
295
|
+
// If specific starts_at filter provided, check if promotion starts at or before it
|
|
296
|
+
const filterStartsAt = new Date(promotionFilter.starts_at);
|
|
297
|
+
if (startsAt > filterStartsAt)
|
|
270
298
|
return false;
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
// Default: only include promotions that have started
|
|
302
|
+
if (startsAt > now)
|
|
274
303
|
return false;
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
// Check ends_at
|
|
307
|
+
if (promo.ends_at) {
|
|
308
|
+
const endsAt = new Date(promo.ends_at);
|
|
309
|
+
if (promotionFilter.ends_at) {
|
|
310
|
+
// If specific ends_at filter provided, check if promotion ends at or after it
|
|
311
|
+
const filterEndsAt = new Date(promotionFilter.ends_at);
|
|
312
|
+
if (endsAt < filterEndsAt)
|
|
280
313
|
return false;
|
|
281
|
-
|
|
282
|
-
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
// Default: only include promotions that haven't ended yet
|
|
317
|
+
if (endsAt < now)
|
|
283
318
|
return false;
|
|
284
|
-
|
|
285
|
-
return true;
|
|
286
|
-
});
|
|
287
|
-
});
|
|
288
|
-
// Update metadata count after filtering
|
|
289
|
-
if (metadata) {
|
|
290
|
-
metadata.count = products.length;
|
|
319
|
+
}
|
|
291
320
|
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
try {
|
|
298
|
-
// Query all promotions (we'll filter in memory)
|
|
299
|
-
// This ensures we don't miss promotions due to query filter limitations
|
|
300
|
-
const promotionQueryOptions = {
|
|
301
|
-
entity: "promotion",
|
|
302
|
-
fields: [
|
|
303
|
-
"id",
|
|
304
|
-
"code",
|
|
305
|
-
"type",
|
|
306
|
-
"application_method.*",
|
|
307
|
-
"campaign.*",
|
|
308
|
-
"rules.*",
|
|
309
|
-
"rules.values.*",
|
|
310
|
-
"starts_at",
|
|
311
|
-
"ends_at",
|
|
312
|
-
"status",
|
|
313
|
-
],
|
|
314
|
-
};
|
|
315
|
-
// Add basic filters if specified
|
|
316
|
-
const promotionQueryFilters = {};
|
|
317
|
-
if (promotionFilter.status) {
|
|
318
|
-
promotionQueryFilters.status = promotionFilter.status;
|
|
321
|
+
else {
|
|
322
|
+
// Open-ended promotion (no ends_at)
|
|
323
|
+
// Include if include_open_ended is true (default) or not explicitly false
|
|
324
|
+
if (promotionFilter.include_open_ended === false) {
|
|
325
|
+
return false;
|
|
319
326
|
}
|
|
320
|
-
|
|
321
|
-
|
|
327
|
+
}
|
|
328
|
+
return true;
|
|
329
|
+
});
|
|
330
|
+
return promotions;
|
|
331
|
+
}
|
|
332
|
+
async extractProductPromotionData(promotions) {
|
|
333
|
+
const productIds = new Set();
|
|
334
|
+
const discounts = new Map();
|
|
335
|
+
let hasUniversalPromotions = false;
|
|
336
|
+
let universalDiscount = 0;
|
|
337
|
+
for (const promotion of promotions) {
|
|
338
|
+
const discount = this.calculateDiscountPercentage(promotion);
|
|
339
|
+
// Debug: Log full promotion structure for first promotion
|
|
340
|
+
if (promotions.indexOf(promotion) === 0) {
|
|
341
|
+
console.log(`[DynamicFilterService] Promotion structure:`, JSON.stringify({
|
|
342
|
+
id: promotion.id,
|
|
343
|
+
code: promotion.code,
|
|
344
|
+
type: promotion.type,
|
|
345
|
+
rules: promotion.rules,
|
|
346
|
+
application_method: promotion.application_method,
|
|
347
|
+
metadata: promotion.metadata
|
|
348
|
+
}, null, 2));
|
|
349
|
+
}
|
|
350
|
+
// Check if promotion has no rules (universal promotion - applies to all products)
|
|
351
|
+
const hasNoRules = !promotion.rules || promotion.rules.length === 0;
|
|
352
|
+
if (hasNoRules) {
|
|
353
|
+
console.log(`[DynamicFilterService] Promotion ${promotion.id || promotion.code} has no rules - applies to all products`);
|
|
354
|
+
hasUniversalPromotions = true;
|
|
355
|
+
if (discount !== undefined && discount > universalDiscount) {
|
|
356
|
+
universalDiscount = discount;
|
|
322
357
|
}
|
|
323
|
-
|
|
324
|
-
|
|
358
|
+
}
|
|
359
|
+
const ids = await this.extractProductIdsFromPromotion(promotion);
|
|
360
|
+
// Debug logging for first promotion
|
|
361
|
+
if (promotions.indexOf(promotion) === 0) {
|
|
362
|
+
console.log(`[DynamicFilterService] Promotion ${promotion.id || promotion.code}: discount=${discount}%, productIds=${ids.length}, universal=${hasNoRules}`);
|
|
363
|
+
if (ids.length > 0) {
|
|
364
|
+
console.log(`[DynamicFilterService] Sample product IDs: ${ids.slice(0, 3).join(", ")}`);
|
|
325
365
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
? new Date(promotion.starts_at)
|
|
339
|
-
: null;
|
|
340
|
-
const endsAt = promotion.ends_at ? new Date(promotion.ends_at) : null;
|
|
341
|
-
if (promotionFilter.starts_at) {
|
|
342
|
-
const filterStart = new Date(promotionFilter.starts_at);
|
|
343
|
-
if (endsAt && endsAt < filterStart) {
|
|
344
|
-
return false; // Promotion ends before filter start
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
if (promotionFilter.ends_at) {
|
|
348
|
-
const filterEnd = new Date(promotionFilter.ends_at);
|
|
349
|
-
if (startsAt && startsAt > filterEnd) {
|
|
350
|
-
return false; // Promotion starts after filter end
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
else {
|
|
355
|
-
// Default: only include promotions active now
|
|
356
|
-
const startsAt = promotion.starts_at
|
|
357
|
-
? new Date(promotion.starts_at)
|
|
358
|
-
: null;
|
|
359
|
-
const endsAt = promotion.ends_at ? new Date(promotion.ends_at) : null;
|
|
360
|
-
if (startsAt && startsAt > now) {
|
|
361
|
-
return false; // Promotion hasn't started yet
|
|
362
|
-
}
|
|
363
|
-
if (endsAt && endsAt < now) {
|
|
364
|
-
return false; // Promotion has ended
|
|
365
|
-
}
|
|
366
|
-
// Include open-ended promotions if include_open_ended is true
|
|
367
|
-
if (!endsAt &&
|
|
368
|
-
promotionFilter.include_open_ended === false) {
|
|
369
|
-
return false; // Exclude open-ended promotions
|
|
370
|
-
}
|
|
366
|
+
else if (!hasNoRules) {
|
|
367
|
+
console.warn(`[DynamicFilterService] No product IDs extracted from promotion ${promotion.id || promotion.code}`);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
// Only add product IDs if promotion has rules
|
|
371
|
+
// Universal promotions (no rules) apply to all products
|
|
372
|
+
if (!hasNoRules) {
|
|
373
|
+
ids.forEach(id => {
|
|
374
|
+
productIds.add(id);
|
|
375
|
+
if (discount !== undefined) {
|
|
376
|
+
const currentMax = discounts.get(id) || 0;
|
|
377
|
+
discounts.set(id, Math.max(currentMax, discount));
|
|
371
378
|
}
|
|
372
|
-
return true;
|
|
373
379
|
});
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
return { productIds, discounts, hasUniversalPromotions, universalDiscount };
|
|
383
|
+
}
|
|
384
|
+
calculateDiscountPercentage(promotion) {
|
|
385
|
+
const appMethod = promotion.application_method;
|
|
386
|
+
if (!appMethod || typeof appMethod !== "object") {
|
|
387
|
+
console.log(`[DynamicFilterService] Promotion ${promotion.id || promotion.code}: No application_method`);
|
|
388
|
+
return undefined;
|
|
389
|
+
}
|
|
390
|
+
// Try to get discount from application_method.type === "percentage"
|
|
391
|
+
if (appMethod.type === "percentage" && "value" in appMethod) {
|
|
392
|
+
const value = typeof appMethod.value === "number" ? appMethod.value : Number(appMethod.value);
|
|
393
|
+
if (!Number.isNaN(value)) {
|
|
394
|
+
console.log(`[DynamicFilterService] Promotion ${promotion.id || promotion.code}: Found percentage discount ${value}% from application_method.type=percentage`);
|
|
395
|
+
return value;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
// Try to get discount from promotion type
|
|
399
|
+
if (promotion.type === "percentage_off_product" || promotion.type === "percentage_off_order") {
|
|
400
|
+
if ("value" in appMethod) {
|
|
401
|
+
const value = typeof appMethod.value === "number" ? appMethod.value : Number(appMethod.value);
|
|
402
|
+
if (!Number.isNaN(value)) {
|
|
403
|
+
console.log(`[DynamicFilterService] Promotion ${promotion.id || promotion.code}: Found percentage discount ${value}% from promotion.type=${promotion.type}`);
|
|
404
|
+
return value;
|
|
385
405
|
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
// Attach rules to promotion object
|
|
410
|
-
promotion.rules = rules;
|
|
411
|
-
}
|
|
412
|
-
else {
|
|
413
|
-
// Try querying with different entity names or structures
|
|
414
|
-
console.log(`[DynamicFilterService] No promotion_rule found for ${promotion.id}, trying alternative queries`);
|
|
415
|
-
// Try querying promotion_rule_value entity
|
|
416
|
-
try {
|
|
417
|
-
const ruleValueQueryResult = await this.query.graph({
|
|
418
|
-
entity: "promotion_rule_value",
|
|
419
|
-
fields: ["id", "value", "promotion_rule_id"],
|
|
420
|
-
filters: {
|
|
421
|
-
promotion_rule: {
|
|
422
|
-
promotion_id: [promotion.id],
|
|
423
|
-
},
|
|
424
|
-
},
|
|
425
|
-
});
|
|
426
|
-
const ruleValues = Array.isArray(ruleValueQueryResult.data)
|
|
427
|
-
? ruleValueQueryResult.data
|
|
428
|
-
: [];
|
|
429
|
-
if (ruleValues.length > 0) {
|
|
430
|
-
console.log(`[DynamicFilterService] Found ${ruleValues.length} rule values for promotion ${promotion.id}`);
|
|
431
|
-
// Extract product IDs from rule values
|
|
432
|
-
for (const ruleValue of ruleValues) {
|
|
433
|
-
if (ruleValue && typeof ruleValue === "object" && "value" in ruleValue) {
|
|
434
|
-
const value = ruleValue.value;
|
|
435
|
-
if (typeof value === "string") {
|
|
436
|
-
// This might be a product ID
|
|
437
|
-
productIdsWithPromotions.add(value);
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
catch (error) {
|
|
444
|
-
console.log(`[DynamicFilterService] Could not query promotion_rule_value:`, error instanceof Error ? error.message : String(error));
|
|
445
|
-
}
|
|
446
|
-
// Try querying the promotion again with deeper expansion
|
|
447
|
-
try {
|
|
448
|
-
const deepPromotionQuery = await this.query.graph({
|
|
449
|
-
entity: "promotion",
|
|
450
|
-
fields: [
|
|
451
|
-
"id",
|
|
452
|
-
"rules.*",
|
|
453
|
-
"rules.values.*",
|
|
454
|
-
"rules.batch_rules.*",
|
|
455
|
-
"rules.batch_rules.values.*",
|
|
456
|
-
],
|
|
457
|
-
filters: {
|
|
458
|
-
id: [promotion.id],
|
|
459
|
-
},
|
|
460
|
-
});
|
|
461
|
-
const deepPromotions = Array.isArray(deepPromotionQuery.data)
|
|
462
|
-
? deepPromotionQuery.data
|
|
463
|
-
: [];
|
|
464
|
-
if (deepPromotions.length > 0 && deepPromotions[0].rules) {
|
|
465
|
-
console.log(`[DynamicFilterService] Found rules with deep expansion:`, JSON.stringify(deepPromotions[0].rules, null, 2));
|
|
466
|
-
promotion.rules = deepPromotions[0].rules;
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
catch (error) {
|
|
470
|
-
console.log(`[DynamicFilterService] Could not query promotion with deep expansion:`, error instanceof Error ? error.message : String(error));
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
catch (error) {
|
|
475
|
-
// Entity might not exist or have different name - that's okay
|
|
476
|
-
console.log(`[DynamicFilterService] Could not query promotion_rule entity (this is normal if rules are embedded):`, error instanceof Error ? error.message : String(error));
|
|
477
|
-
}
|
|
478
|
-
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
console.log(`[DynamicFilterService] Promotion ${promotion.id || promotion.code}: Could not calculate discount percentage. type=${promotion.type}, appMethod.type=${appMethod.type}, appMethod.value=${appMethod.value}`);
|
|
409
|
+
return undefined;
|
|
410
|
+
}
|
|
411
|
+
async extractProductIdsFromPromotion(promotion) {
|
|
412
|
+
const productIds = new Set();
|
|
413
|
+
// Debug: Log rule structure
|
|
414
|
+
if (promotion.rules?.length) {
|
|
415
|
+
console.log(`[DynamicFilterService] Processing ${promotion.rules.length} rules for promotion ${promotion.id || promotion.code}`);
|
|
416
|
+
for (const rule of promotion.rules) {
|
|
417
|
+
const ruleType = rule.type || rule.attribute || "";
|
|
418
|
+
const normalizedType = String(ruleType).toLowerCase();
|
|
419
|
+
console.log(`[DynamicFilterService] Rule: type=${ruleType}, attribute=${rule.attribute}, values=`, rule.values);
|
|
420
|
+
// Skip rules that definitely don't contain product IDs
|
|
421
|
+
if (normalizedType &&
|
|
422
|
+
(normalizedType === "customer_groups" ||
|
|
423
|
+
normalizedType === "regions" ||
|
|
424
|
+
normalizedType === "currency" ||
|
|
425
|
+
normalizedType === "customer_group" ||
|
|
426
|
+
normalizedType === "region")) {
|
|
427
|
+
console.log(`[DynamicFilterService] Skipping non-product rule: ${ruleType}`);
|
|
428
|
+
continue;
|
|
479
429
|
}
|
|
480
|
-
//
|
|
481
|
-
//
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
let discountPercentage;
|
|
500
|
-
const applicationMethod = promotion.application_method;
|
|
501
|
-
if (applicationMethod &&
|
|
502
|
-
typeof applicationMethod === "object" &&
|
|
503
|
-
"type" in applicationMethod) {
|
|
504
|
-
const appMethodType = applicationMethod.type;
|
|
505
|
-
if (appMethodType === "fixed" &&
|
|
506
|
-
"target_type" in applicationMethod &&
|
|
507
|
-
applicationMethod.target_type === "items") {
|
|
508
|
-
// Fixed amount discount on items (amount_off_product)
|
|
509
|
-
// Will calculate percentage per product later
|
|
510
|
-
discountPercentage = undefined;
|
|
511
|
-
}
|
|
512
|
-
else if (appMethodType === "percentage" &&
|
|
513
|
-
"target_type" in applicationMethod &&
|
|
514
|
-
applicationMethod.target_type === "items") {
|
|
515
|
-
// Percentage discount on items (percentage_off_product)
|
|
516
|
-
if ("value" in applicationMethod) {
|
|
517
|
-
discountPercentage =
|
|
518
|
-
typeof applicationMethod.value === "number"
|
|
519
|
-
? applicationMethod.value
|
|
520
|
-
: Number(applicationMethod.value);
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
else if (appMethodType === "percentage" &&
|
|
524
|
-
"target_type" in applicationMethod &&
|
|
525
|
-
applicationMethod.target_type === "order") {
|
|
526
|
-
// Order-level percentage discount
|
|
527
|
-
if ("value" in applicationMethod) {
|
|
528
|
-
discountPercentage =
|
|
529
|
-
typeof applicationMethod.value === "number"
|
|
530
|
-
? applicationMethod.value
|
|
531
|
-
: Number(applicationMethod.value);
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
else if (appMethodType === "free_shipping") {
|
|
535
|
-
// Free shipping - consider as 0% for product filtering
|
|
536
|
-
discountPercentage = 0;
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
// Fallback: Check promotion.type for backward compatibility
|
|
540
|
-
if (discountPercentage === undefined && promotion.type) {
|
|
541
|
-
if (promotion.type === "percentage_off_product") {
|
|
542
|
-
if (applicationMethod &&
|
|
543
|
-
typeof applicationMethod === "object" &&
|
|
544
|
-
"value" in applicationMethod) {
|
|
545
|
-
discountPercentage =
|
|
546
|
-
typeof applicationMethod.value === "number"
|
|
547
|
-
? applicationMethod.value
|
|
548
|
-
: Number(applicationMethod.value);
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
else if (promotion.type === "amount_off_product") {
|
|
552
|
-
// Will calculate per product
|
|
553
|
-
discountPercentage = undefined;
|
|
554
|
-
}
|
|
555
|
-
else if (promotion.type === "percentage_off_order") {
|
|
556
|
-
if (applicationMethod &&
|
|
557
|
-
typeof applicationMethod === "object" &&
|
|
558
|
-
"value" in applicationMethod) {
|
|
559
|
-
discountPercentage =
|
|
560
|
-
typeof applicationMethod.value === "number"
|
|
561
|
-
? applicationMethod.value
|
|
562
|
-
: Number(applicationMethod.value);
|
|
563
|
-
}
|
|
430
|
+
// Process all other rules (including product-related ones)
|
|
431
|
+
// In Medusa v2, rules.values can be:
|
|
432
|
+
// - An array of strings (product IDs)
|
|
433
|
+
// - An array of objects with id/value fields
|
|
434
|
+
// - A single value
|
|
435
|
+
let values = [];
|
|
436
|
+
if (Array.isArray(rule.values)) {
|
|
437
|
+
values = rule.values;
|
|
438
|
+
}
|
|
439
|
+
else if (rule.values !== undefined && rule.values !== null) {
|
|
440
|
+
values = [rule.values];
|
|
441
|
+
}
|
|
442
|
+
console.log(`[DynamicFilterService] Processing ${values.length} values from rule ${ruleType}`);
|
|
443
|
+
for (const value of values) {
|
|
444
|
+
if (typeof value === "string") {
|
|
445
|
+
// String values could be product IDs
|
|
446
|
+
if (value.length > 0) {
|
|
447
|
+
console.log(`[DynamicFilterService] Adding product ID from string: ${value}`);
|
|
448
|
+
productIds.add(value);
|
|
564
449
|
}
|
|
565
450
|
}
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
const ruleAttribute = rule.attribute;
|
|
573
|
-
if (ruleAttribute === "items" ||
|
|
574
|
-
ruleAttribute === "product_id" ||
|
|
575
|
-
ruleAttribute === "product_ids") {
|
|
576
|
-
// Direct product targeting
|
|
577
|
-
const productIds = Array.isArray(rule.values)
|
|
578
|
-
? rule.values
|
|
579
|
-
: rule.values
|
|
580
|
-
? [rule.values]
|
|
581
|
-
: [];
|
|
582
|
-
for (const productId of productIds) {
|
|
583
|
-
if (typeof productId === "string") {
|
|
584
|
-
productIdsWithPromotions.add(productId);
|
|
585
|
-
// Track maximum discount percentage for this product
|
|
586
|
-
if (discountPercentage !== undefined) {
|
|
587
|
-
const currentMax = promotionDiscountMap.get(productId) || 0;
|
|
588
|
-
promotionDiscountMap.set(productId, Math.max(currentMax, discountPercentage));
|
|
589
|
-
}
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
else if (ruleAttribute === "product_collection_id" ||
|
|
594
|
-
ruleAttribute === "product_collection_ids" ||
|
|
595
|
-
ruleAttribute === "collection_id" ||
|
|
596
|
-
ruleAttribute === "collection_ids") {
|
|
597
|
-
// Collection-based targeting - we'll need to get products from collections
|
|
598
|
-
// For now, we'll query products by collection_id
|
|
599
|
-
const collectionIds = Array.isArray(rule.values)
|
|
600
|
-
? rule.values
|
|
601
|
-
: rule.values
|
|
602
|
-
? [rule.values]
|
|
603
|
-
: [];
|
|
604
|
-
// Query products in these collections
|
|
605
|
-
for (const collectionId of collectionIds) {
|
|
606
|
-
if (typeof collectionId === "string") {
|
|
607
|
-
const collectionProductsResult = await this.query.graph({
|
|
608
|
-
entity: "product",
|
|
609
|
-
fields: ["id"],
|
|
610
|
-
filters: {
|
|
611
|
-
collection_id: [collectionId],
|
|
612
|
-
},
|
|
613
|
-
});
|
|
614
|
-
const collectionProducts = Array.isArray(collectionProductsResult.data)
|
|
615
|
-
? collectionProductsResult.data
|
|
616
|
-
: [];
|
|
617
|
-
for (const product of collectionProducts) {
|
|
618
|
-
if (product && typeof product === "object" && "id" in product) {
|
|
619
|
-
const productId = product.id;
|
|
620
|
-
productIdsWithPromotions.add(productId);
|
|
621
|
-
if (discountPercentage !== undefined) {
|
|
622
|
-
const currentMax = promotionDiscountMap.get(productId) || 0;
|
|
623
|
-
promotionDiscountMap.set(productId, Math.max(currentMax, discountPercentage));
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
}
|
|
451
|
+
else if (typeof value === "object" && value !== null) {
|
|
452
|
+
// Handle object values - could be { id: "prod_123" } or similar
|
|
453
|
+
console.log(`[DynamicFilterService] Processing object value:`, value);
|
|
454
|
+
if ("id" in value && typeof value.id === "string") {
|
|
455
|
+
console.log(`[DynamicFilterService] Adding product ID from object.id: ${value.id}`);
|
|
456
|
+
productIds.add(value.id);
|
|
630
457
|
}
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
// OR the products might be stored in a different way (e.g., join table, metadata, etc.)
|
|
635
|
-
const applicationMethod = promotion.application_method;
|
|
636
|
-
if (applicationMethod &&
|
|
637
|
-
typeof applicationMethod === "object" &&
|
|
638
|
-
"target_type" in applicationMethod &&
|
|
639
|
-
applicationMethod.target_type === "items") {
|
|
640
|
-
console.log(`[DynamicFilterService] Promotion ${promotion.id} targets items but has no rules`);
|
|
641
|
-
// Try to find products associated with this promotion through alternative methods
|
|
642
|
-
// Option 1: Check if products are stored in promotion metadata
|
|
643
|
-
if (promotion.metadata && typeof promotion.metadata === "object") {
|
|
644
|
-
const metadata = promotion.metadata;
|
|
645
|
-
if (metadata.product_ids && Array.isArray(metadata.product_ids)) {
|
|
646
|
-
console.log(`[DynamicFilterService] Found product_ids in promotion metadata`);
|
|
647
|
-
const productIds = metadata.product_ids;
|
|
648
|
-
for (const productId of productIds) {
|
|
649
|
-
if (typeof productId === "string") {
|
|
650
|
-
productIdsWithPromotions.add(productId);
|
|
651
|
-
if (discountPercentage !== undefined) {
|
|
652
|
-
const currentMax = promotionDiscountMap.get(productId) || 0;
|
|
653
|
-
promotionDiscountMap.set(productId, Math.max(currentMax, discountPercentage));
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
// Option 2: If no rules and no metadata product_ids,
|
|
660
|
-
// and the promotion is active, we might need to include all products
|
|
661
|
-
// BUT this is risky - only do it if explicitly configured
|
|
662
|
-
// For now, we'll log and skip products for promotions without rules
|
|
663
|
-
console.log(`[DynamicFilterService] Skipping products for promotion ${promotion.id} - no rules found and no product_ids in metadata`);
|
|
458
|
+
else if ("value" in value && typeof value.value === "string") {
|
|
459
|
+
console.log(`[DynamicFilterService] Adding product ID from object.value: ${value.value}`);
|
|
460
|
+
productIds.add(value.value);
|
|
664
461
|
}
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
console.log(`[DynamicFilterService] Found ${productIdsWithPromotions.size} products with promotions`);
|
|
669
|
-
// FALLBACK: If no products found but we have promotions targeting items without rules,
|
|
670
|
-
// include all products (this is a workaround for when rules aren't queryable)
|
|
671
|
-
if (productIdsWithPromotions.size === 0 && promotions.length > 0) {
|
|
672
|
-
const itemsTargetingPromotions = promotions.filter((p) => {
|
|
673
|
-
const appMethod = p.application_method;
|
|
674
|
-
return (appMethod &&
|
|
675
|
-
typeof appMethod === "object" &&
|
|
676
|
-
"target_type" in appMethod &&
|
|
677
|
-
appMethod.target_type === "items" &&
|
|
678
|
-
(!p.rules || p.rules.length === 0));
|
|
679
|
-
});
|
|
680
|
-
if (itemsTargetingPromotions.length > 0) {
|
|
681
|
-
console.log(`[DynamicFilterService] FALLBACK: Found ${itemsTargetingPromotions.length} promotions targeting items with no rules. ` +
|
|
682
|
-
`Including all products as fallback (promotion rules may be stored in a way we can't query yet).`);
|
|
683
|
-
// Include all current products and set their discount percentages
|
|
684
|
-
for (const product of products) {
|
|
685
|
-
if (product && typeof product === "object" && "id" in product) {
|
|
686
|
-
const productId = product.id;
|
|
687
|
-
productIdsWithPromotions.add(productId);
|
|
688
|
-
// Calculate and set discount percentage for each promotion
|
|
689
|
-
for (const promo of itemsTargetingPromotions) {
|
|
690
|
-
const appMethod = promo.application_method;
|
|
691
|
-
if (appMethod &&
|
|
692
|
-
typeof appMethod === "object" &&
|
|
693
|
-
"type" in appMethod &&
|
|
694
|
-
appMethod.type === "percentage" &&
|
|
695
|
-
"value" in appMethod) {
|
|
696
|
-
const discount = typeof appMethod.value === "number"
|
|
697
|
-
? appMethod.value
|
|
698
|
-
: Number(appMethod.value);
|
|
699
|
-
if (!Number.isNaN(discount)) {
|
|
700
|
-
const currentMax = promotionDiscountMap.get(productId) || 0;
|
|
701
|
-
promotionDiscountMap.set(productId, Math.max(currentMax, discount));
|
|
702
|
-
}
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
}
|
|
462
|
+
else if ("product_id" in value && typeof value.product_id === "string") {
|
|
463
|
+
console.log(`[DynamicFilterService] Adding product ID from object.product_id: ${value.product_id}`);
|
|
464
|
+
productIds.add(value.product_id);
|
|
706
465
|
}
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
}
|
|
714
|
-
// Filter products to only include those with matching promotions
|
|
715
|
-
products = products.filter((product) => {
|
|
716
|
-
const productId = product?.id;
|
|
717
|
-
if (!productId || typeof productId !== "string") {
|
|
718
|
-
return false;
|
|
719
|
-
}
|
|
720
|
-
// Check if product has a matching promotion
|
|
721
|
-
if (!productIdsWithPromotions.has(productId)) {
|
|
722
|
-
return false;
|
|
723
|
-
}
|
|
724
|
-
// If min_discount_percentage is specified, check discount
|
|
725
|
-
if (promotionFilter.min_discount_percentage !== undefined) {
|
|
726
|
-
const productDiscount = promotionDiscountMap.get(productId);
|
|
727
|
-
// For amount_off_product (fixed amount discount), calculate percentage from product price
|
|
728
|
-
if (productDiscount === undefined && product.variants) {
|
|
729
|
-
// Try to find promotion with fixed amount discount on items
|
|
730
|
-
// and calculate percentage from product price
|
|
731
|
-
const productPrice = product.variants?.[0]?.prices?.[0]?.amount;
|
|
732
|
-
if (productPrice && typeof productPrice === "number") {
|
|
733
|
-
// Find matching promotion with amount discount
|
|
734
|
-
for (const promotion of promotions) {
|
|
735
|
-
const applicationMethod = promotion.application_method;
|
|
736
|
-
const isAmountDiscount = (applicationMethod &&
|
|
737
|
-
typeof applicationMethod === "object" &&
|
|
738
|
-
"type" in applicationMethod &&
|
|
739
|
-
applicationMethod.type === "fixed" &&
|
|
740
|
-
"target_type" in applicationMethod &&
|
|
741
|
-
applicationMethod.target_type === "items") ||
|
|
742
|
-
promotion.type === "amount_off_product";
|
|
743
|
-
if (isAmountDiscount) {
|
|
744
|
-
if (applicationMethod &&
|
|
745
|
-
typeof applicationMethod === "object" &&
|
|
746
|
-
"value" in applicationMethod) {
|
|
747
|
-
const discountAmount = typeof applicationMethod.value === "number"
|
|
748
|
-
? applicationMethod.value
|
|
749
|
-
: Number(applicationMethod.value);
|
|
750
|
-
if (!Number.isNaN(discountAmount) && productPrice > 0) {
|
|
751
|
-
const calculatedPercentage = (discountAmount / productPrice) * 100;
|
|
752
|
-
const currentMax = promotionDiscountMap.get(productId) || 0;
|
|
753
|
-
promotionDiscountMap.set(productId, Math.max(currentMax, calculatedPercentage));
|
|
754
|
-
}
|
|
755
|
-
}
|
|
756
|
-
}
|
|
466
|
+
else {
|
|
467
|
+
// Try to extract any string field that looks like an ID
|
|
468
|
+
for (const [key, val] of Object.entries(value)) {
|
|
469
|
+
if (typeof val === "string" && val.length > 0 && (val.startsWith("prod_") || key.toLowerCase().includes("id"))) {
|
|
470
|
+
console.log(`[DynamicFilterService] Adding product ID from object.${key}: ${val}`);
|
|
471
|
+
productIds.add(val);
|
|
757
472
|
}
|
|
758
473
|
}
|
|
759
474
|
}
|
|
760
|
-
const finalDiscount = promotionDiscountMap.get(productId) || 0;
|
|
761
|
-
// Check if discount meets minimum threshold
|
|
762
|
-
if (finalDiscount < promotionFilter.min_discount_percentage) {
|
|
763
|
-
return false;
|
|
764
|
-
}
|
|
765
475
|
}
|
|
766
|
-
return true;
|
|
767
|
-
});
|
|
768
|
-
// Update metadata count after filtering
|
|
769
|
-
if (metadata) {
|
|
770
|
-
metadata.count = products.length;
|
|
771
476
|
}
|
|
772
477
|
}
|
|
773
|
-
catch (error) {
|
|
774
|
-
// Log error but don't fail - return products without promotion filtering
|
|
775
|
-
console.warn("[DynamicFilterService] Error filtering by promotions:", error instanceof Error ? error.message : String(error));
|
|
776
|
-
}
|
|
777
478
|
}
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
479
|
+
else {
|
|
480
|
+
console.log(`[DynamicFilterService] No rules found in promotion ${promotion.id || promotion.code}`);
|
|
481
|
+
}
|
|
482
|
+
// Also check metadata for product IDs (fallback)
|
|
483
|
+
if (promotion.metadata?.product_ids?.length) {
|
|
484
|
+
console.log(`[DynamicFilterService] Found product IDs in metadata:`, promotion.metadata.product_ids);
|
|
485
|
+
promotion.metadata.product_ids.forEach((id) => {
|
|
486
|
+
if (typeof id === "string") {
|
|
487
|
+
productIds.add(id);
|
|
488
|
+
}
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
const result = Array.from(productIds);
|
|
492
|
+
console.log(`[DynamicFilterService] Extracted ${result.length} product IDs:`, result);
|
|
493
|
+
return result;
|
|
494
|
+
}
|
|
495
|
+
meetsDiscountCriteria(discount, promotionFilter) {
|
|
496
|
+
if (promotionFilter.min_discount_percentage !== undefined &&
|
|
497
|
+
discount < promotionFilter.min_discount_percentage) {
|
|
498
|
+
return false;
|
|
499
|
+
}
|
|
500
|
+
if (promotionFilter.max_discount_percentage !== undefined &&
|
|
501
|
+
discount > promotionFilter.max_discount_percentage) {
|
|
502
|
+
return false;
|
|
503
|
+
}
|
|
504
|
+
return true;
|
|
505
|
+
}
|
|
506
|
+
async getCount(queryFilters, metadata, productsLength) {
|
|
507
|
+
if (metadata?.count !== undefined)
|
|
508
|
+
return metadata.count;
|
|
509
|
+
try {
|
|
510
|
+
const countResult = await this.query.graph({
|
|
783
511
|
entity: "product",
|
|
784
512
|
fields: ["id"],
|
|
785
513
|
...(Object.keys(queryFilters).length > 0 && { filters: queryFilters }),
|
|
786
|
-
};
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
else if (Array.isArray(countData)) {
|
|
794
|
-
count = countData.length;
|
|
795
|
-
}
|
|
796
|
-
else {
|
|
797
|
-
// Fallback: use products array length if count query also fails
|
|
798
|
-
console.warn("[DynamicFilterService] Could not determine count from query result, using products array length");
|
|
799
|
-
count = products.length;
|
|
800
|
-
}
|
|
514
|
+
});
|
|
515
|
+
return countResult.metadata?.count ||
|
|
516
|
+
(Array.isArray(countResult.data) ? countResult.data.length : productsLength);
|
|
517
|
+
}
|
|
518
|
+
catch (error) {
|
|
519
|
+
console.warn("[DynamicFilterService] Could not determine count:", error);
|
|
520
|
+
return productsLength;
|
|
801
521
|
}
|
|
802
|
-
return {
|
|
803
|
-
products,
|
|
804
|
-
count: typeof count === "number" ? count : products.length,
|
|
805
|
-
metadata: {
|
|
806
|
-
count: typeof count === "number" ? count : products.length,
|
|
807
|
-
skip: pagination?.offset,
|
|
808
|
-
take: pagination?.limit,
|
|
809
|
-
},
|
|
810
|
-
};
|
|
811
522
|
}
|
|
812
523
|
}
|
|
813
524
|
exports.DynamicFilterService = DynamicFilterService;
|
|
814
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHluYW1pYy1maWx0ZXItc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9zZXJ2aWNlcy9keW5hbWljLWZpbHRlci1zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUNBLHFEQUFtRjtBQUVuRix5RUFBbUU7QUE2RG5FOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBc0JHO0FBQ0gsTUFBYSxvQkFBb0I7SUFJL0IsWUFBWSxTQUEwQjtRQUNwQywrQ0FBK0M7UUFDL0MsSUFBSSxDQUFDO1lBQ0gsSUFBSSxDQUFDLFFBQVEsR0FBRyxTQUFTLENBQUMsT0FBTyxDQUMvQix3QkFBd0IsQ0FDekIsQ0FBQTtRQUNILENBQUM7UUFBQyxNQUFNLENBQUM7WUFDUCwwRUFBMEU7WUFDMUUseUVBQXlFO1lBQ3pFLElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxpREFBc0IsRUFBRSxDQUFBO1lBRTVDLG1DQUFtQztZQUNuQyxJQUFJLENBQUM7Z0JBQ0gsTUFBTSxFQUFFLHdCQUF3QixFQUFFLEdBQUcsT0FBTyxDQUFDLCtCQUErQixDQUFDLENBQUE7Z0JBQzdFLHdCQUF3QixDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQTtZQUN6QyxDQUFDO1lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztnQkFDZiwwQ0FBMEM7Z0JBQzFDLE9BQU8sQ0FBQyxJQUFJLENBQ1Ysb0VBQW9FLEVBQ3BFLEtBQUssWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FDdkQsQ0FBQTtZQUNILENBQUM7UUFDSCxDQUFDO1FBQ0QsSUFBSSxDQUFDLEtBQUssR0FBRyxTQUFTLENBQUMsT0FBTyxDQUFRLGlDQUF5QixDQUFDLEtBQUssQ0FBQyxDQUFBO0lBQ3hFLENBQUM7SUFFRDs7O09BR0c7SUFDSCxXQUFXO1FBQ1QsT0FBTyxJQUFJLENBQUMsUUFB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
|
|
525
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHluYW1pYy1maWx0ZXItc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9zZXJ2aWNlcy9keW5hbWljLWZpbHRlci1zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUNBLHFEQUFxRTtBQUNyRSx5RUFBbUU7QUFrQm5FLE1BQWEsb0JBQW9CO0lBSS9CLFlBQVksU0FBMEI7UUFDcEMsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDLFNBQVMsQ0FBQyxDQUFBO1FBQy9DLElBQUksQ0FBQyxLQUFLLEdBQUcsU0FBUyxDQUFDLE9BQU8sQ0FBUSxpQ0FBeUIsQ0FBQyxLQUFLLENBQUMsQ0FBQTtJQUN4RSxDQUFDO0lBRUQsV0FBVztRQUNULE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQTtJQUN0QixDQUFDO0lBRUQsS0FBSyxDQUFDLFlBQVksQ0FBQyxPQUE0QjtRQUM3QyxNQUFNLEVBQUUsWUFBWSxFQUFFLE9BQU8sRUFBRSxhQUFhLEVBQUUsVUFBVSxFQUFFLFVBQVUsRUFBRSxPQUFPLEdBQUcsRUFBRSxFQUFFLEdBQUcsT0FBTyxDQUFBO1FBQzlGLE1BQU0sYUFBYSxHQUFrQixFQUFFLEdBQUcsT0FBTyxFQUFFLE9BQU8sRUFBRSxhQUFhLEVBQUUsQ0FBQTtRQUUzRSxNQUFNLEVBQUUsWUFBWSxFQUFFLGdCQUFnQixFQUFFLGVBQWUsRUFBRSxHQUFHLE1BQU0sSUFBSSxDQUFDLGNBQWMsQ0FBQyxZQUFZLEVBQUUsYUFBYSxDQUFDLENBQUE7UUFFbEgsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxVQUFVLEVBQUUsTUFBTSxDQUFDLENBQUE7UUFDbkQsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixDQUFDLE9BQU8sQ0FBQyxDQUFBO1FBQ3BELE1BQU0sWUFBWSxHQUFHLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxZQUFZLEVBQUUsTUFBTSxFQUFF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
|