pim-import 5.0.1 → 5.0.3

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.
Files changed (249) hide show
  1. package/dist/algolia/clean.js +0 -1
  2. package/dist/algolia/config.js +0 -1
  3. package/dist/algolia/downloads.js +0 -1
  4. package/dist/algolia/families.js +0 -1
  5. package/dist/algolia/inspirations.js +0 -1
  6. package/dist/algolia/models.js +0 -1
  7. package/dist/algolia/news.js +0 -1
  8. package/dist/algolia/pressRelease.js +0 -1
  9. package/dist/algolia/pressReview.js +0 -1
  10. package/dist/algolia/products.js +0 -1
  11. package/dist/algolia/projects.js +0 -1
  12. package/dist/algolia/stories.js +0 -1
  13. package/dist/algolia/subFamilies.js +0 -1
  14. package/dist/algolia/subModels.js +0 -1
  15. package/dist/browser.js +0 -1
  16. package/dist/downloads/classes/manageEntry.js +0 -1
  17. package/dist/downloads/import.js +0 -1
  18. package/dist/index.js +0 -1
  19. package/dist/libs/contentful-cda.js +0 -1
  20. package/dist/libs/contentful.js +0 -1
  21. package/dist/libs/imgix.js +0 -1
  22. package/dist/libs/logs.js +0 -1
  23. package/dist/libs/netlify.js +0 -1
  24. package/dist/libs/notifications.js +0 -1
  25. package/dist/libs/pdf.js +0 -1
  26. package/dist/libs/s3.js +0 -1
  27. package/dist/libs/sentry.js +0 -1
  28. package/dist/pim/config.js +0 -1
  29. package/dist/pim/endpoints.js +0 -1
  30. package/dist/pim/methods/bulkPublish.js +0 -1
  31. package/dist/pim/methods/catalogs.js +0 -1
  32. package/dist/pim/methods/checkTopicDraftAndPagePublished.js +0 -1
  33. package/dist/pim/methods/designers.js +0 -1
  34. package/dist/pim/methods/dictionary.js +0 -1
  35. package/dist/pim/methods/families.js +0 -1
  36. package/dist/pim/methods/latestProducts.js +0 -1
  37. package/dist/pim/methods/migrateEntryFields.js +0 -1
  38. package/dist/pim/methods/models.js +0 -1
  39. package/dist/pim/methods/pages/catalogs.js +0 -1
  40. package/dist/pim/methods/pages/families.js +0 -1
  41. package/dist/pim/methods/pages/subfamilies.js +0 -1
  42. package/dist/pim/methods/products.js +0 -1
  43. package/dist/pim/methods/subfamilies.js +0 -1
  44. package/dist/pim/methods/submodels.js +0 -1
  45. package/dist/pim/request.js +0 -1
  46. package/dist/resources/AllProducts.js +0 -1
  47. package/dist/resources/Audit.js +0 -1
  48. package/dist/resources/CatalogDetails.js +0 -1
  49. package/dist/resources/CollectionModels.js +0 -1
  50. package/dist/resources/CollectionSubFamilies.js +0 -1
  51. package/dist/resources/CollectionSubModels.js +0 -1
  52. package/dist/resources/DProductSubLine.js +0 -1
  53. package/dist/resources/FamilyDetails.js +0 -1
  54. package/dist/resources/ProductDetails.js +0 -1
  55. package/dist/resources/ProductRelation.js +0 -1
  56. package/dist/resources/cfFields.js +0 -1
  57. package/dist/types.js +0 -1
  58. package/dist/utils.js +0 -1
  59. package/package.json +7 -2
  60. package/.env.example +0 -45
  61. package/.nvmrc +0 -1
  62. package/.vscode/settings.json +0 -21
  63. package/dist/algolia/clean.js.map +0 -1
  64. package/dist/algolia/config.js.map +0 -1
  65. package/dist/algolia/downloads.js.map +0 -1
  66. package/dist/algolia/families.js.map +0 -1
  67. package/dist/algolia/inspirations.js.map +0 -1
  68. package/dist/algolia/models.js.map +0 -1
  69. package/dist/algolia/news.js.map +0 -1
  70. package/dist/algolia/pressRelease.js.map +0 -1
  71. package/dist/algolia/pressReview.js.map +0 -1
  72. package/dist/algolia/products.js.map +0 -1
  73. package/dist/algolia/projects.js.map +0 -1
  74. package/dist/algolia/stories.js.map +0 -1
  75. package/dist/algolia/subFamilies.js.map +0 -1
  76. package/dist/algolia/subModels.js.map +0 -1
  77. package/dist/browser.js.map +0 -1
  78. package/dist/downloads/classes/manageEntry.js.map +0 -1
  79. package/dist/downloads/import.js.map +0 -1
  80. package/dist/index.js.map +0 -1
  81. package/dist/libs/contentful-cda.js.map +0 -1
  82. package/dist/libs/contentful.js.map +0 -1
  83. package/dist/libs/imgix.js.map +0 -1
  84. package/dist/libs/logs.js.map +0 -1
  85. package/dist/libs/netlify.js.map +0 -1
  86. package/dist/libs/notifications.js.map +0 -1
  87. package/dist/libs/pdf.js.map +0 -1
  88. package/dist/libs/s3.js.map +0 -1
  89. package/dist/libs/sentry.js.map +0 -1
  90. package/dist/pim/config.js.map +0 -1
  91. package/dist/pim/endpoints.js.map +0 -1
  92. package/dist/pim/methods/bulkPublish.js.map +0 -1
  93. package/dist/pim/methods/catalogs.js.map +0 -1
  94. package/dist/pim/methods/checkTopicDraftAndPagePublished.js.map +0 -1
  95. package/dist/pim/methods/designers.js.map +0 -1
  96. package/dist/pim/methods/dictionary.js.map +0 -1
  97. package/dist/pim/methods/families.js.map +0 -1
  98. package/dist/pim/methods/latestProducts.js.map +0 -1
  99. package/dist/pim/methods/migrateEntryFields.js.map +0 -1
  100. package/dist/pim/methods/models.js.map +0 -1
  101. package/dist/pim/methods/pages/catalogs.js.map +0 -1
  102. package/dist/pim/methods/pages/families.js.map +0 -1
  103. package/dist/pim/methods/pages/subfamilies.js.map +0 -1
  104. package/dist/pim/methods/products.js.map +0 -1
  105. package/dist/pim/methods/subfamilies.js.map +0 -1
  106. package/dist/pim/methods/submodels.js.map +0 -1
  107. package/dist/pim/request.js.map +0 -1
  108. package/dist/resources/AllProducts.js.map +0 -1
  109. package/dist/resources/Audit.js.map +0 -1
  110. package/dist/resources/CatalogDetails.js.map +0 -1
  111. package/dist/resources/CollectionModels.js.map +0 -1
  112. package/dist/resources/CollectionSubFamilies.js.map +0 -1
  113. package/dist/resources/CollectionSubModels.js.map +0 -1
  114. package/dist/resources/DProductSubLine.js.map +0 -1
  115. package/dist/resources/FamilyDetails.js.map +0 -1
  116. package/dist/resources/ProductDetails.js.map +0 -1
  117. package/dist/resources/ProductRelation.js.map +0 -1
  118. package/dist/resources/cfFields.js.map +0 -1
  119. package/dist/types.js.map +0 -1
  120. package/dist/utils.js.map +0 -1
  121. package/docs/import-data-from-the-dictionary.md +0 -83
  122. package/docs/import-products.md +0 -61
  123. package/docs/import-taxonomies-from-the-catalog.md +0 -60
  124. package/docs/settings.md +0 -47
  125. package/jest.config.js +0 -16
  126. package/local-fn/reindex.js +0 -182
  127. package/src/algolia/clean.ts +0 -164
  128. package/src/algolia/config.ts +0 -390
  129. package/src/algolia/downloads.ts +0 -346
  130. package/src/algolia/families.ts +0 -652
  131. package/src/algolia/inspirations.ts +0 -315
  132. package/src/algolia/models.ts +0 -589
  133. package/src/algolia/news.ts +0 -258
  134. package/src/algolia/pressRelease.ts +0 -255
  135. package/src/algolia/pressReview.ts +0 -247
  136. package/src/algolia/products.ts +0 -731
  137. package/src/algolia/projects.ts +0 -339
  138. package/src/algolia/stories.ts +0 -347
  139. package/src/algolia/subFamilies.ts +0 -709
  140. package/src/algolia/subModels.ts +0 -359
  141. package/src/browser.ts +0 -122
  142. package/src/downloads/classes/manageEntry.ts +0 -99
  143. package/src/downloads/csv/legal.csv +0 -5
  144. package/src/downloads/csv/products.csv +0 -373
  145. package/src/downloads/import.ts +0 -381
  146. package/src/index.ts +0 -140
  147. package/src/libs/contentful-cda.ts +0 -543
  148. package/src/libs/contentful.ts +0 -1453
  149. package/src/libs/imgix.ts +0 -297
  150. package/src/libs/logs.ts +0 -121
  151. package/src/libs/netlify.ts +0 -37
  152. package/src/libs/notifications.ts +0 -104
  153. package/src/libs/pdf.ts +0 -107
  154. package/src/libs/s3.ts +0 -305
  155. package/src/libs/sentry.ts +0 -33
  156. package/src/pim/config.ts +0 -84
  157. package/src/pim/data/productFields.json +0 -1178
  158. package/src/pim/endpoints.ts +0 -364
  159. package/src/pim/methods/bulkPublish.ts +0 -266
  160. package/src/pim/methods/catalogs.ts +0 -586
  161. package/src/pim/methods/checkTopicDraftAndPagePublished.ts +0 -70
  162. package/src/pim/methods/designers.ts +0 -128
  163. package/src/pim/methods/dictionary.ts +0 -611
  164. package/src/pim/methods/families.ts +0 -345
  165. package/src/pim/methods/latestProducts.ts +0 -70
  166. package/src/pim/methods/migrateEntryFields.ts +0 -99
  167. package/src/pim/methods/models.ts +0 -349
  168. package/src/pim/methods/pages/catalogs.ts +0 -28
  169. package/src/pim/methods/pages/families.ts +0 -50
  170. package/src/pim/methods/pages/subfamilies.ts +0 -98
  171. package/src/pim/methods/products.ts +0 -3297
  172. package/src/pim/methods/subfamilies.ts +0 -706
  173. package/src/pim/methods/submodels.ts +0 -262
  174. package/src/pim/request.ts +0 -61
  175. package/src/resources/AllProducts.ts +0 -41
  176. package/src/resources/Audit.ts +0 -24
  177. package/src/resources/CatalogDetails.ts +0 -51
  178. package/src/resources/CollectionModels.ts +0 -42
  179. package/src/resources/CollectionSubFamilies.ts +0 -45
  180. package/src/resources/CollectionSubModels.ts +0 -36
  181. package/src/resources/DProductSubLine.ts +0 -34
  182. package/src/resources/FamilyDetails.ts +0 -31
  183. package/src/resources/ProductDetails.ts +0 -352
  184. package/src/resources/ProductRelation.ts +0 -24
  185. package/src/resources/cfFields.ts +0 -8
  186. package/src/types.ts +0 -268
  187. package/src/utils.ts +0 -553
  188. package/tsconfig.json +0 -93
  189. package/tslint.json +0 -22
  190. package/types/libs/puppeteer.d.ts +0 -17
  191. package/types/pim/methods/checkIp.d.ts +0 -1
  192. /package/{types → dist}/algolia/clean.d.ts +0 -0
  193. /package/{types → dist}/algolia/config.d.ts +0 -0
  194. /package/{types → dist}/algolia/downloads.d.ts +0 -0
  195. /package/{types → dist}/algolia/families.d.ts +0 -0
  196. /package/{types → dist}/algolia/inspirations.d.ts +0 -0
  197. /package/{types → dist}/algolia/models.d.ts +0 -0
  198. /package/{types → dist}/algolia/news.d.ts +0 -0
  199. /package/{types → dist}/algolia/pressRelease.d.ts +0 -0
  200. /package/{types → dist}/algolia/pressReview.d.ts +0 -0
  201. /package/{types → dist}/algolia/products.d.ts +0 -0
  202. /package/{types → dist}/algolia/projects.d.ts +0 -0
  203. /package/{types → dist}/algolia/stories.d.ts +0 -0
  204. /package/{types → dist}/algolia/subFamilies.d.ts +0 -0
  205. /package/{types → dist}/algolia/subModels.d.ts +0 -0
  206. /package/{types → dist}/browser.d.ts +0 -0
  207. /package/{types → dist}/downloads/classes/manageEntry.d.ts +0 -0
  208. /package/{types → dist}/downloads/import.d.ts +0 -0
  209. /package/{types → dist}/index.d.ts +0 -0
  210. /package/{types → dist}/libs/contentful-cda.d.ts +0 -0
  211. /package/{types → dist}/libs/contentful.d.ts +0 -0
  212. /package/{types → dist}/libs/imgix.d.ts +0 -0
  213. /package/{types → dist}/libs/logs.d.ts +0 -0
  214. /package/{types → dist}/libs/netlify.d.ts +0 -0
  215. /package/{types → dist}/libs/notifications.d.ts +0 -0
  216. /package/{types → dist}/libs/pdf.d.ts +0 -0
  217. /package/{types → dist}/libs/s3.d.ts +0 -0
  218. /package/{types → dist}/libs/sentry.d.ts +0 -0
  219. /package/{types → dist}/pim/config.d.ts +0 -0
  220. /package/{types → dist}/pim/endpoints.d.ts +0 -0
  221. /package/{types → dist}/pim/methods/bulkPublish.d.ts +0 -0
  222. /package/{types → dist}/pim/methods/catalogs.d.ts +0 -0
  223. /package/{types → dist}/pim/methods/checkTopicDraftAndPagePublished.d.ts +0 -0
  224. /package/{types → dist}/pim/methods/designers.d.ts +0 -0
  225. /package/{types → dist}/pim/methods/dictionary.d.ts +0 -0
  226. /package/{types → dist}/pim/methods/families.d.ts +0 -0
  227. /package/{types → dist}/pim/methods/latestProducts.d.ts +0 -0
  228. /package/{types → dist}/pim/methods/migrateEntryFields.d.ts +0 -0
  229. /package/{types → dist}/pim/methods/models.d.ts +0 -0
  230. /package/{types → dist}/pim/methods/pages/catalogs.d.ts +0 -0
  231. /package/{types → dist}/pim/methods/pages/families.d.ts +0 -0
  232. /package/{types → dist}/pim/methods/pages/subfamilies.d.ts +0 -0
  233. /package/{types → dist}/pim/methods/products.d.ts +0 -0
  234. /package/{types → dist}/pim/methods/subfamilies.d.ts +0 -0
  235. /package/{types → dist}/pim/methods/submodels.d.ts +0 -0
  236. /package/{types → dist}/pim/request.d.ts +0 -0
  237. /package/{types → dist}/resources/AllProducts.d.ts +0 -0
  238. /package/{types → dist}/resources/Audit.d.ts +0 -0
  239. /package/{types → dist}/resources/CatalogDetails.d.ts +0 -0
  240. /package/{types → dist}/resources/CollectionModels.d.ts +0 -0
  241. /package/{types → dist}/resources/CollectionSubFamilies.d.ts +0 -0
  242. /package/{types → dist}/resources/CollectionSubModels.d.ts +0 -0
  243. /package/{types → dist}/resources/DProductSubLine.d.ts +0 -0
  244. /package/{types → dist}/resources/FamilyDetails.d.ts +0 -0
  245. /package/{types → dist}/resources/ProductDetails.d.ts +0 -0
  246. /package/{types → dist}/resources/ProductRelation.d.ts +0 -0
  247. /package/{types → dist}/resources/cfFields.d.ts +0 -0
  248. /package/{types → dist}/types.d.ts +0 -0
  249. /package/{types → dist}/utils.d.ts +0 -0
@@ -1,3297 +0,0 @@
1
- import {
2
- ProductDetails,
3
- AssetsEntity,
4
- ColourVariant,
5
- } from "../../resources/ProductDetails";
6
- import { AllProductsEntry } from "../../resources/AllProducts";
7
- import { ProductRelation } from "../../resources/ProductRelation";
8
- import { FieldItem } from "../../resources/cfFields";
9
- import { Audit } from "../../resources/Audit";
10
- import {
11
- AvailableCatalogs,
12
- CfLocalizedEntryField,
13
- WrapperImageFields,
14
- CfSys,
15
- } from "../../types";
16
- import { log, serverUtils } from "../../libs/logs";
17
- import {
18
- getEntryByCode,
19
- getAllEntriesByCodes,
20
- getEnvironmentDefaultLocaleCode,
21
- createEntryWithId,
22
- cfLocales,
23
- getEntryByID,
24
- updateEntry,
25
- getEnvironment,
26
- addFieldValue,
27
- addToRelationFields,
28
- removeFromRelationFields,
29
- removeFromFieldObject,
30
- createWrapperImgix,
31
- getDictionaryLocaleValue,
32
- getDictionaryJson,
33
- getAllEntries,
34
- archiveEntry,
35
- } from "../../libs/contentful";
36
- import type {
37
- Entry,
38
- CreateEntryProps,
39
- } from "contentful-management/dist/typings/entities/entry";
40
- import { KeyValueMap } from "contentful-management/dist/typings/common-types";
41
- import {
42
- stringToSlug,
43
- secondBetweenTwoDate,
44
- sleep,
45
- getLocalISOTime,
46
- capitalizeFirstLetter,
47
- sanitizeValue,
48
- getPimTranslations,
49
- basename,
50
- } from "../../utils";
51
- import {
52
- saveAllProductsToS3,
53
- getFileFromS3,
54
- saveJsonToS3,
55
- upload as uploadToS3,
56
- } from "../../libs/s3";
57
- import { getAudit, getProductDetails } from "../endpoints";
58
- import { getCategoryTopicCode } from "./catalogs";
59
- import productFieldsRequiredData from "../data/productFields.json";
60
- import {
61
- getDefaultWrapperImgixAttributesByPimUrl,
62
- getImgixPimUrlByOriginPath,
63
- getOriginPathByPimUrl,
64
- purgeImageCacheByUrl,
65
- } from "../../libs/imgix";
66
- import { generatePDFByUrl } from "../../libs/pdf";
67
- import { reindexProduct } from "../../algolia/products";
68
- import { addDesignerData } from "./designers";
69
- import { notify } from "../../libs/notifications";
70
-
71
- export type AvailableProductStatus =
72
- | "To be review"
73
- | "Published"
74
- | "Unpublished";
75
-
76
- export type AvailableRelationFieldKeys =
77
- | "accessories"
78
- | "accessoryOf"
79
- | "bulbOf"
80
- | "sparepartOf"
81
- | "bulbs"
82
- | "spareparts";
83
-
84
- const PIM_DUPLICATE_SEPARATOR: string = "~";
85
- const S3_PIM_PAYLOAD_PATH = `pim/payload/`;
86
-
87
- /**
88
- * Check if the sku passed belongs to a product which should not be imported
89
- * but which needs to be used to create product associations -> additional taxonomy terms.
90
- *
91
- * It returns false only if it is an product that needs to be imported or the the updated productEntry
92
- *
93
- * @param productDetails
94
- * @returns peoductEntry or boolean
95
- */
96
- const isTermsToAdd = async (
97
- productDetails: ProductDetails,
98
- catalog: AvailableCatalogs
99
- ): Promise<Entry | boolean> => {
100
- if (!productDetails.code.includes(PIM_DUPLICATE_SEPARATOR)) {
101
- return false;
102
- }
103
- log(
104
- `Product used to create associations between product and additional taxonomy terms: ${productDetails.code}`
105
- );
106
-
107
- const realCode = productDetails.code.substring(
108
- 0,
109
- productDetails.code.indexOf(PIM_DUPLICATE_SEPARATOR)
110
- );
111
-
112
- let productEntry: Entry = await getEntryByCode(realCode, "topicProduct");
113
- if (!productEntry) {
114
- log(
115
- `The product ${realCode} does not exist, it is not possible to save the additional association with the ${productDetails?.currentCatalog?.subFamilyCode} family and the ${productDetails?.currentCatalog?.categoryCode} category`
116
- );
117
- return true;
118
- } else if (productEntry.isArchived()) {
119
- log(
120
- `The product ${realCode} is archived, it is not possible to save the additional association with the ${productDetails?.currentCatalog?.subFamilyCode} family and the ${productDetails?.currentCatalog?.categoryCode} category`
121
- );
122
- return true;
123
- }
124
-
125
- // product -> catalog relation
126
- const catalogFieldKey = "catalogs";
127
- if (productDetails.currentCatalog?.catalogCode) {
128
- const catalogEntry: Entry = await getEntryByCode(
129
- productDetails.currentCatalog.catalogCode,
130
- "topicCatalog",
131
- "sys"
132
- );
133
- if (catalogEntry) {
134
- log(
135
- `Start the association of the ${realCode} with the ${productDetails.currentCatalog.catalogCode} catalog`
136
- );
137
-
138
- productEntry.fields = await addToRelationFields(
139
- productEntry,
140
- catalogFieldKey,
141
- catalogEntry.sys.id,
142
- true
143
- );
144
- } else {
145
- log(
146
- `The ${productDetails.currentCatalog.catalogCode} catalog does not exist`
147
- );
148
- }
149
- } else {
150
- log(`No catalog code found`, "WARN");
151
- }
152
-
153
- // product -> category relation
154
- const categoriesFieldKey = "categories" + capitalizeFirstLetter(catalog);
155
- if (productDetails.currentCatalog?.categoryCode) {
156
- const categoryTopicCode = getCategoryTopicCode(
157
- productDetails.currentCatalog.categoryCode,
158
- catalog
159
- );
160
- const categoryEntry: Entry = await getEntryByCode(
161
- categoryTopicCode,
162
- "topicCategory",
163
- "sys"
164
- );
165
- if (categoryEntry) {
166
- log(
167
- `Start the association of the ${realCode} with the ${categoryTopicCode} category`
168
- );
169
- productEntry.fields = await addToRelationFields(
170
- productEntry,
171
- categoriesFieldKey,
172
- categoryEntry.sys.id,
173
- true
174
- );
175
- } else {
176
- log(`The ${categoryTopicCode} category does not exist`);
177
- }
178
- } else {
179
- log(`No category code found`, "WARN");
180
- }
181
-
182
- // product -> family relation
183
- const familiesFieldKey = "families";
184
- if (productDetails.currentCatalog?.familyCode) {
185
- const familyEntry: Entry = await getEntryByCode(
186
- productDetails.currentCatalog.familyCode,
187
- "topicFamily",
188
- "sys"
189
- );
190
- if (familyEntry) {
191
- log(
192
- `Start the association of the ${realCode} with the ${productDetails.currentCatalog.familyCode} family`
193
- );
194
-
195
- productEntry.fields = await addToRelationFields(
196
- productEntry,
197
- familiesFieldKey,
198
- familyEntry.sys.id,
199
- true
200
- );
201
- } else {
202
- log(
203
- `The ${productDetails.currentCatalog.familyCode} family does not exist`
204
- );
205
- }
206
- } else {
207
- log(`No family code found`, "WARN");
208
- }
209
-
210
- // product -> subFamily relation
211
- const subFamiliesFieldKey = "subFamilies" + capitalizeFirstLetter(catalog);
212
- if (productDetails.currentCatalog?.subFamilyCode) {
213
- const subFamilyEntry: Entry = await getEntryByCode(
214
- productDetails.currentCatalog.subFamilyCode,
215
- "topicSubFamily",
216
- "sys"
217
- );
218
- if (subFamilyEntry) {
219
- log(
220
- `Start the association of the ${realCode} with the ${productDetails?.currentCatalog?.subFamilyCode} subFamily`
221
- );
222
-
223
- productEntry.fields = await addToRelationFields(
224
- productEntry,
225
- subFamiliesFieldKey,
226
- subFamilyEntry.sys.id,
227
- true
228
- );
229
- } else {
230
- log(
231
- `The ${productDetails.currentCatalog.subFamilyCode} subFamily does not exist`
232
- );
233
- }
234
- } else {
235
- log(`No subFamily code found`, "WARN");
236
- }
237
-
238
- // product -> model relations
239
- const modelsFieldKey = "models" + capitalizeFirstLetter(catalog);
240
- if (productDetails.models) {
241
- for (const model of productDetails.models) {
242
- const modelCode = model.data.code;
243
- if (modelCode) {
244
- log(`Get model entry with id ${modelCode}`);
245
- const modelEntry = await getEntryByID(modelCode, "topicModel", "sys");
246
- if (modelEntry) {
247
- log(
248
- `Start the association of the ${realCode} with the ${modelCode} model`
249
- );
250
- productEntry.fields = await addToRelationFields(
251
- productEntry,
252
- modelsFieldKey,
253
- modelEntry.sys.id,
254
- true
255
- );
256
- } else {
257
- log(`The ${modelCode} model does not exist`);
258
- }
259
- } else {
260
- log(`No model code found`, "WARN");
261
- }
262
- }
263
- } else {
264
- log(`No models found`);
265
- }
266
-
267
- // product -> submodel relations
268
- const subModelsFieldKey = "subModels" + capitalizeFirstLetter(catalog);
269
- if (productDetails.submodels) {
270
- for (const submodel of productDetails.submodels) {
271
- const subModelCode = submodel.data.code;
272
- if (subModelCode) {
273
- log(`Get subModel entry with id ${subModelCode}`);
274
- const subModelEntry = await getEntryByID(
275
- subModelCode,
276
- "topicSubModel",
277
- "sys"
278
- );
279
- if (subModelEntry) {
280
- log(
281
- `Start the association of the ${realCode} with the ${subModelCode} subModel`
282
- );
283
- productEntry.fields = await addToRelationFields(
284
- productEntry,
285
- subModelsFieldKey,
286
- subModelEntry.sys.id,
287
- true
288
- );
289
- } else {
290
- log(`The ${subModelCode} subModel does not exist`);
291
- }
292
- } else {
293
- log(`No subModel code found`, "WARN");
294
- }
295
- }
296
- } else {
297
- log(`No subModel found`);
298
- }
299
-
300
- productEntry = await productEntry.update();
301
- if (productEntry.isPublished()) {
302
- try {
303
- productEntry = await productEntry.publish();
304
- } catch (err: any) {
305
- log(`Cannot publish entry.`);
306
- log(err);
307
- }
308
- }
309
-
310
- return productEntry;
311
- };
312
-
313
- const notVisibleToWebProduct = async (code: string): Promise<void> => {
314
- // topicProduct
315
- let productEntry: Entry = await getEntryByCode(code, "topicProduct");
316
- if (productEntry) {
317
- const pageId = getProductPageIdByCode(productEntry.sys.id);
318
-
319
- log("The product exists, I proceed to archive it");
320
- productEntry = await archiveEntry(productEntry, true);
321
- // page
322
- let pageEntry = await getEntryByID(pageId, "page");
323
- if (pageEntry) {
324
- pageEntry = await archiveEntry(pageEntry);
325
- }
326
- } else {
327
- log("The product has never been imported", "WARN");
328
- }
329
- };
330
-
331
- export const setHideInRegionField = async (
332
- destinations: string[],
333
- pageData: CreateEntryProps
334
- ) => {
335
- const env = await getEnvironment();
336
- const defEnvLocaleCode = await getEnvironmentDefaultLocaleCode();
337
-
338
- let productRegions = destinations
339
- ?.filter(
340
- (item: any) =>
341
- item?.code?.includes("PROFESSIONAL_") ||
342
- (typeof item === "string" && item?.includes("PROFESSIONAL_"))
343
- )
344
- .map((item: any) => {
345
- const region =
346
- item?.code?.replace("PROFESSIONAL_", "")?.toLowerCase() ||
347
- item?.replace("PROFESSIONAL_", "")?.toLowerCase();
348
- return region === "china" ? "cn" : region;
349
- });
350
-
351
- /*
352
- Aggiunto per risolvere il problema sul sito Cina:
353
-
354
- se sono nascoste in global => lascio hide in regions CN
355
- se non sono nascoste in global => tolgo hide in regions CN
356
- */
357
- if (productRegions.includes("global") && !productRegions.includes("cn")) {
358
- productRegions.push("cn");
359
- }
360
-
361
- if (pageData.fields.hideInRegions?.[defEnvLocaleCode]) {
362
- pageData.fields.hideInRegions[defEnvLocaleCode] = [];
363
- }
364
-
365
- if (productRegions?.length) {
366
- log(`Hide from other regions other than: ${productRegions.join(", ")}`);
367
- const { items } = await env.getEntries({
368
- content_type: "topicRegion",
369
- limit: 100,
370
- skip: 0,
371
- locale: defEnvLocaleCode,
372
- include: 0,
373
- select: "sys,fields",
374
- });
375
- let count = 0;
376
- for (const item of items) {
377
- const region = item?.fields?.region?.[defEnvLocaleCode];
378
-
379
- if (!productRegions.includes(region)) {
380
- log(`Hide in region: ${region}`);
381
- pageData.fields = await addToRelationFields(
382
- pageData,
383
- "hideInRegions",
384
- item.sys.id,
385
- true,
386
- count++ === 0
387
- );
388
- }
389
- }
390
- } else if (pageData.fields?.hideInRegions?.[defEnvLocaleCode]) {
391
- log(`No region found remove old hideInRegions relations.`);
392
- } else {
393
- log(`No region found.`, "WARN");
394
- }
395
-
396
- return pageData.fields;
397
- };
398
-
399
- const getProductPageData = async (
400
- names: CfLocalizedEntryField,
401
- slugs: CfLocalizedEntryField,
402
- pageId: string,
403
- productEntry: Entry,
404
- productPageEntry: Entry
405
- ): Promise<CreateEntryProps> => {
406
- const defEnvLocaleCode = await getEnvironmentDefaultLocaleCode();
407
- const pageData: CreateEntryProps = {
408
- fields: productPageEntry?.fields || {},
409
- };
410
-
411
- pageData.fields.title = names;
412
- pageData.fields.slug = slugs;
413
-
414
- pageData.fields = await addFieldValue(pageData, "internalName", pageId);
415
- pageData.fields = await addFieldValue(pageData, "type", "CatalogProduct");
416
-
417
- // Topic
418
- pageData.fields = await addToRelationFields(
419
- pageData,
420
- "topic",
421
- productEntry.sys.id
422
- );
423
-
424
- // hideInRegions
425
- const destinations =
426
- productEntry?.fields?.productFields?.[defEnvLocaleCode]?.destinations;
427
- pageData.fields = await setHideInRegionField(destinations, pageData);
428
- return pageData;
429
- };
430
-
431
- const createOrUpdateProductPage = async (
432
- productEntry: Entry,
433
- unpublish: boolean
434
- ): Promise<Entry> => {
435
- const pageId = getProductPageIdByCode(productEntry.sys.id);
436
- const names: CfLocalizedEntryField = productEntry.fields.name;
437
- const slugs: any = {};
438
- const code = productEntry.fields.code["en"];
439
-
440
- for (const name of Object.entries(productEntry.fields.name)) {
441
- slugs[name[0]] = stringToSlug(`${name[1]}-${code}`, true).toLowerCase();
442
- }
443
-
444
- // PAGE
445
- let productPageEntry: Entry = await getEntryByID(pageId, "page");
446
- const pageData: CreateEntryProps = await getProductPageData(
447
- names,
448
- slugs,
449
- pageId,
450
- productEntry,
451
- productPageEntry
452
- );
453
- if (productPageEntry) {
454
- if (productPageEntry.isArchived()) {
455
- log(`Unarchive product page with id ${pageId}`);
456
- productPageEntry = await productPageEntry.unarchive();
457
- }
458
- log(`Product page ${pageId} already exists. Updating...`);
459
- productPageEntry = await updateEntry(
460
- productPageEntry,
461
- pageData,
462
- productPageEntry.isPublished() && !unpublish
463
- );
464
- } else {
465
- log(`Product page ${pageId} not exists. Create new entry with data`);
466
- productPageEntry = await createEntryWithId("page", pageId, pageData);
467
- }
468
-
469
- return productPageEntry;
470
- };
471
-
472
- export const certificationFields = ["certification", "marking"];
473
- export const excludeCertificationFieldsKeys = [
474
- "designAwards",
475
- "energyLabel",
476
- "lightObjMinDist",
477
- "ilcos",
478
- "dynamicLoad",
479
- "staticLoad",
480
- "casambi",
481
- "fMarking",
482
- ];
483
-
484
- const getProductFields = async (pimDetails: any) => {
485
- const defaultEnvironmentLocaleCode = await getEnvironmentDefaultLocaleCode();
486
- const productFields: any = {};
487
- productFieldsRequiredData.forEach((fieldData) => {
488
- if (fieldData.parent) {
489
- if (
490
- pimDetails?.[fieldData.parent]?.[fieldData.key] ||
491
- pimDetails?.[fieldData.parent]?.[fieldData.key] === false
492
- ) {
493
- if (Array.isArray(pimDetails[fieldData.parent][fieldData.key])) {
494
- pimDetails[fieldData.parent][fieldData.key].forEach((item: any) => {
495
- if (
496
- item.code &&
497
- sanitizeValue(item.code) &&
498
- sanitizeValue(item[`value_${defaultEnvironmentLocaleCode}`])
499
- ) {
500
- if (!productFields?.[fieldData.parent]?.[fieldData.key]) {
501
- if (!productFields?.[fieldData.parent]) {
502
- productFields[fieldData.parent] = {};
503
- }
504
- productFields[fieldData.parent][fieldData.key] = [];
505
- }
506
-
507
- productFields[fieldData.parent][fieldData.key].push({
508
- code: item.code,
509
- parentName: item?.parentName || "",
510
- });
511
- }
512
- });
513
- } else {
514
- let value: any = "";
515
- if (
516
- pimDetails?.[fieldData.parent]?.[fieldData.key]?.code &&
517
- sanitizeValue(pimDetails[fieldData.parent][fieldData.key].code) &&
518
- sanitizeValue(
519
- pimDetails[fieldData.parent][fieldData.key][
520
- `value_${defaultEnvironmentLocaleCode}`
521
- ]
522
- )
523
- ) {
524
- value = {
525
- code:
526
- pimDetails[fieldData.parent][fieldData.key]?.code ||
527
- pimDetails[fieldData.parent][fieldData.key] ||
528
- "",
529
- parentName:
530
- pimDetails[fieldData.parent][fieldData.key]?.parentName || "",
531
- };
532
- } else if (
533
- (pimDetails?.[fieldData.parent]?.[fieldData.key]?.state &&
534
- sanitizeValue(
535
- pimDetails[fieldData.parent][fieldData.key].state
536
- )) ||
537
- pimDetails[fieldData.parent][fieldData.key].state === false
538
- ) {
539
- value = {
540
- state: !!pimDetails[fieldData.parent][fieldData.key].state,
541
- label:
542
- pimDetails[fieldData.parent][fieldData.key]?.label?.[
543
- `value_${defaultEnvironmentLocaleCode}`
544
- ] || "",
545
- };
546
- } else if (
547
- typeof pimDetails[fieldData.parent][fieldData.key] !== "object" &&
548
- (sanitizeValue(pimDetails[fieldData.parent][fieldData.key]) ||
549
- pimDetails[fieldData.parent][fieldData.key] === false)
550
- ) {
551
- value = pimDetails[fieldData.parent][fieldData.key];
552
- }
553
-
554
- if (value || value === false) {
555
- if (!productFields[fieldData.parent]) {
556
- productFields[fieldData.parent] = {};
557
- }
558
-
559
- productFields[fieldData.parent][fieldData.key] = value;
560
- }
561
- }
562
- } else {
563
- log(
564
- `${fieldData.parent}.${fieldData.key} product field not found on the pim or null`
565
- );
566
- }
567
- } else {
568
- if (pimDetails.hasOwnProperty(fieldData.key)) {
569
- if (Array.isArray(pimDetails[fieldData.key])) {
570
- pimDetails[fieldData.key].forEach((item: any) => {
571
- if (
572
- item.code &&
573
- sanitizeValue(item.code) &&
574
- sanitizeValue(item[`value_${defaultEnvironmentLocaleCode}`])
575
- ) {
576
- if (!productFields?.[fieldData.key]) {
577
- productFields[fieldData.key] = [];
578
- }
579
- productFields[fieldData.key].push({
580
- code: item.code,
581
- parentName: item?.parentName || "",
582
- });
583
- }
584
- });
585
- } else {
586
- let value: any = "";
587
- if (
588
- pimDetails[fieldData.key]?.code &&
589
- sanitizeValue(pimDetails[fieldData.key].code) &&
590
- sanitizeValue(
591
- pimDetails[fieldData.key][`value_${defaultEnvironmentLocaleCode}`]
592
- )
593
- ) {
594
- value = {
595
- code:
596
- pimDetails[fieldData.key]?.code ||
597
- pimDetails[fieldData.key] ||
598
- "",
599
- parentName: pimDetails[fieldData.key]?.parentName || "",
600
- };
601
- } else if (
602
- typeof pimDetails[fieldData.key] !== "object" &&
603
- (sanitizeValue(pimDetails[fieldData.key]) ||
604
- pimDetails[fieldData.key] === false)
605
- ) {
606
- value = pimDetails[fieldData.key];
607
- }
608
- if (value || value === false) {
609
- productFields[fieldData.key] = value;
610
- }
611
- }
612
- } else {
613
- log(`${fieldData.key} product field not found on the pim`);
614
- }
615
- }
616
- });
617
-
618
- productFields.certifications = [];
619
- for (const certificationField of certificationFields) {
620
- if (productFields?.[certificationField]) {
621
- log(`Manage certifications field: ${certificationField}`);
622
- for (const [key, values] of Object.entries(
623
- productFields[certificationField]
624
- )) {
625
- if (!excludeCertificationFieldsKeys.includes(key)) {
626
- log(`Add ${key} values to productFields.certifications`);
627
- productFields.certifications =
628
- productFields.certifications.concat(values);
629
- }
630
- }
631
- }
632
- }
633
- if (productFields.certifications.length) {
634
- log(`Remove unwanted values to productFields.certifications`);
635
- productFields.certifications = productFields.certifications.filter(
636
- (value: any) => {
637
- return sanitizeValue(value?.code);
638
- }
639
- );
640
- }
641
-
642
- return productFields;
643
- };
644
-
645
- const getTopicProductIdByCode = (productCode: string) => {
646
- return productCode;
647
- };
648
-
649
- export const getProductPageIdByCode = (productCode: string) => {
650
- return `${productCode}_PAGE`;
651
- };
652
-
653
- const getProductPayloadS3Details = (topicProductId: string) => {
654
- return { path: S3_PIM_PAYLOAD_PATH, fileName: `${topicProductId}.json` };
655
- };
656
-
657
- const getProductAssets = async (
658
- pimAssets: AssetsEntity[],
659
- productCode: string
660
- ) => {
661
- const assets: any = {};
662
- for (const pimAsset of pimAssets) {
663
- if (pimAsset?.url && pimAsset?.assetType?.code) {
664
- const assetCode = pimAsset?.assetType?.code;
665
- const md5 = pimAsset?.md5;
666
-
667
- if (!assetCode || !md5) {
668
- log(
669
- `No assetCode or md5 found for product: ${productCode} assetURL: ${pimAsset.url}`,
670
- "WARN"
671
- );
672
- continue;
673
- }
674
-
675
- if (!assets?.[assetCode]) {
676
- assets[assetCode] = [];
677
- }
678
-
679
- let assetUrl: string = "";
680
- const pimDomain = "dam.flos.net";
681
- const fileExtension = pimAsset.url.split(".")?.pop()?.toLowerCase() || "";
682
- if (
683
- process.env.FPI_IMGIX_PIM_IMAGE_DOMAIN &&
684
- pimAsset.url.indexOf(pimDomain) !== -1 &&
685
- ["jpg", "png", "gif"].includes(fileExtension)
686
- ) {
687
- assetUrl = pimAsset.url.replace(
688
- pimDomain,
689
- process.env.FPI_IMGIX_PIM_IMAGE_DOMAIN
690
- );
691
- } else if (["svg"].includes(fileExtension)) {
692
- assetUrl = pimAsset.url;
693
- } else {
694
- const path = `product-assets/${md5}`;
695
- const fileName = basename(pimAsset.url);
696
-
697
- // FIXME: Trovare un modo per rintracciare i file già esistenti, l'unico parametro utilizzabile è l'MD5
698
- // Se esistono file con lo stesso filename ma diverso MD5 questi verranno caricati più volte
699
- const assetAlreadyExists = await getFileFromS3(
700
- `${path}/${fileName}`,
701
- true
702
- );
703
- if (assetAlreadyExists) {
704
- log(`Asset aleady exists: ${assetAlreadyExists}`);
705
- assetUrl = assetAlreadyExists;
706
- } else {
707
- log(`Asset not exists, importing it to S3 path: ${path}/${fileName}`);
708
- try {
709
- const res = await uploadToS3(pimAsset.url, fileName, path);
710
- assetUrl = res.Location;
711
- } catch (err: any) {
712
- log(
713
- `Unable to upload file: ${err.response.status} - ${err.response.statusText}`,
714
- "WARN"
715
- );
716
- }
717
- }
718
- }
719
-
720
- if (assetUrl) {
721
- assets[assetCode].push(assetUrl);
722
- }
723
- } else {
724
- log(
725
- `The asset ${pimAsset?.assetType} cannot be imported because the url or assetType.code parameters are empty`,
726
- "WARN"
727
- );
728
- }
729
- }
730
-
731
- return assets;
732
- };
733
-
734
- const getProductData = async (
735
- productEntry: Entry,
736
- productDetails: ProductDetails
737
- ) => {
738
- const defaultEnvironmentLocaleCode = await getEnvironmentDefaultLocaleCode();
739
-
740
- const data: CreateEntryProps = {
741
- fields: productEntry?.fields || {},
742
- };
743
-
744
- data.fields.name = getPimTranslations(
745
- productDetails,
746
- "webNaming",
747
- productDetails.name,
748
- 255
749
- );
750
- data.fields = await addFieldValue(data, "code", productDetails.code);
751
-
752
- data.fields.description = getPimTranslations(productDetails, "description1");
753
- data.fields.excerpt = getPimTranslations(productDetails, "description2");
754
- data.fields.note = getPimTranslations(productDetails, "note");
755
-
756
- const { currentCatalog, ...pimDetails } = productDetails;
757
-
758
- log(`Set productFields`);
759
- const productFields = await getProductFields(pimDetails);
760
- data.fields = await addFieldValue(data, "productFields", productFields);
761
-
762
- // catalogs
763
- const catalog = productDetails?.currentCatalog?.catalogCode || "";
764
- if (catalog) {
765
- const catalogEntry: Entry = await getEntryByCode(
766
- catalog,
767
- "topicCatalog",
768
- "sys"
769
- );
770
- log(`Set catalog relation: ${catalog}`);
771
- data.fields = await addToRelationFields(
772
- data,
773
- "catalogs",
774
- catalogEntry.sys.id,
775
- true
776
- );
777
- }
778
-
779
- // categories - for catalg
780
- const categoriesFieldKey = "categories" + capitalizeFirstLetter(catalog);
781
- if (catalog && productDetails?.currentCatalog?.categoryCode) {
782
- const categoryTopicCode = getCategoryTopicCode(
783
- productDetails.currentCatalog.categoryCode,
784
- catalog
785
- );
786
- const categoryEntry: Entry = await getEntryByCode(
787
- categoryTopicCode,
788
- "topicCategory",
789
- "sys"
790
- );
791
- if (!categoryEntry) {
792
- log(`The topicCategory with code ${categoryTopicCode} not found`, "WARN");
793
- } else {
794
- log(
795
- `Set category relation: ${categoryTopicCode} in the field ${categoriesFieldKey}`
796
- );
797
- data.fields = await addToRelationFields(
798
- data,
799
- categoriesFieldKey,
800
- categoryEntry.sys.id,
801
- true
802
- );
803
- }
804
- }
805
-
806
- // families
807
- if (productDetails?.currentCatalog?.familyCode) {
808
- const familyEntry: Entry = await getEntryByCode(
809
- productDetails.currentCatalog.familyCode,
810
- "topicFamily",
811
- "sys"
812
- );
813
- if (!familyEntry) {
814
- log(
815
- `The topicFamily with code ${productDetails.currentCatalog.familyCode} not found`,
816
- "WARN"
817
- );
818
- } else {
819
- log(`Set family relation: ${productDetails.currentCatalog.familyCode}`);
820
- data.fields = await addToRelationFields(
821
- data,
822
- "families",
823
- familyEntry.sys.id,
824
- true
825
- );
826
- }
827
- }
828
-
829
- // subFamilies - for catalg
830
- const subFamiliesFieldKey = "subFamilies" + capitalizeFirstLetter(catalog);
831
- if (productDetails?.currentCatalog?.subFamilyCode) {
832
- const subFamilyEntry: Entry = await getEntryByCode(
833
- productDetails.currentCatalog.subFamilyCode,
834
- "topicSubFamily",
835
- "sys"
836
- );
837
-
838
- if (!subFamilyEntry) {
839
- log(
840
- `The topicSubFamily with code ${productDetails.currentCatalog.subFamilyCode} not found`,
841
- "WARN"
842
- );
843
- } else {
844
- log(
845
- `Set subFamily relation: ${productDetails.currentCatalog.subFamilyCode} in the field ${subFamiliesFieldKey}`
846
- );
847
- data.fields = await addToRelationFields(
848
- data,
849
- subFamiliesFieldKey,
850
- subFamilyEntry.sys.id,
851
- true
852
- );
853
- }
854
- }
855
-
856
- // productLine
857
- if (productDetails?.productLine) {
858
- const productLineEntry: Entry = await getEntryByCode(
859
- productDetails.productLine.code,
860
- "topicProductLine",
861
- "sys"
862
- );
863
- if (!productLineEntry) {
864
- log(
865
- `The topicProductLine with code ${productDetails.productLine.code} not found`,
866
- "WARN"
867
- );
868
- } else {
869
- log(`Set productLine relation: ${productDetails.productLine.code}`);
870
- data.fields = await addToRelationFields(
871
- data,
872
- "productLine",
873
- productLineEntry.sys.id
874
- );
875
- }
876
- }
877
-
878
- // productSubLine
879
- if (productDetails?.productLineDetail) {
880
- const productSubLineEntry: Entry = await getEntryByCode(
881
- productDetails.productLineDetail.code,
882
- "topicProductSubLine",
883
- "sys"
884
- );
885
- if (!productSubLineEntry) {
886
- log(
887
- `The topicProductSubLine with code ${productDetails.productLineDetail.code} not found`,
888
- "WARN"
889
- );
890
- } else {
891
- log(
892
- `Set productSubLine relation: ${productDetails.productLineDetail.code}`
893
- );
894
- data.fields = await addToRelationFields(
895
- data,
896
- "productSubLine",
897
- productSubLineEntry.sys.id
898
- );
899
- }
900
- }
901
-
902
- // models - for catalg
903
- const modelsFieldKey = "models" + capitalizeFirstLetter(catalog);
904
- if (productDetails?.models) {
905
- log(`Set ${productDetails.models.length} model relations`);
906
- const modelCodes = productDetails.models.map((model) => {
907
- return model.data.code;
908
- });
909
-
910
- const topicModelEntries = await getAllEntriesByCodes(
911
- modelCodes,
912
- "topicModel",
913
- "sys,fields.catalog"
914
- );
915
-
916
- if (topicModelEntries.length) {
917
- for (const topicModelEntry of topicModelEntries) {
918
- if (
919
- topicModelEntry?.fields?.catalog?.[defaultEnvironmentLocaleCode]?.sys
920
- ?.id !== catalog
921
- ) {
922
- log(
923
- `The model ${topicModelEntry.sys.id} belongs to the catalog ${topicModelEntry?.fields?.catalog?.[defaultEnvironmentLocaleCode]?.sys?.id} and will not be imported`
924
- );
925
- continue;
926
- } else {
927
- log(
928
- `Set relation with model ${topicModelEntry.sys.id} in the field ${modelsFieldKey}`
929
- );
930
- data.fields = await addToRelationFields(
931
- data,
932
- modelsFieldKey,
933
- topicModelEntry.sys.id,
934
- true
935
- );
936
- }
937
- }
938
- } else {
939
- log(
940
- `No topicModel found for product ${
941
- productDetails.code
942
- }: ${modelCodes.join(",")}`,
943
- "WARN"
944
- );
945
- }
946
- }
947
-
948
- // subModels for catalog
949
- const subModelsFieldKey = "subModels" + capitalizeFirstLetter(catalog);
950
- if (productDetails?.submodels) {
951
- log(`Set ${productDetails.submodels.length} subModels relations`);
952
- const subModelsCodes = productDetails.submodels.map((subModel) => {
953
- return subModel.data.code;
954
- });
955
-
956
- const topicSubModelEntries = await getAllEntriesByCodes(
957
- subModelsCodes,
958
- "topicSubModel",
959
- "sys,fields.catalog"
960
- );
961
-
962
- if (topicSubModelEntries.length) {
963
- for (const topicSubModelEntry of topicSubModelEntries) {
964
- if (
965
- topicSubModelEntry?.fields?.catalog?.[defaultEnvironmentLocaleCode]
966
- ?.sys?.id !== catalog
967
- ) {
968
- log(
969
- `The subModel ${topicSubModelEntry.sys.id} belongs to the catalog ${topicSubModelEntry?.fields?.catalog?.[defaultEnvironmentLocaleCode]?.sys?.id} and will not be imported`
970
- );
971
- continue;
972
- } else {
973
- log(
974
- `Set relation with subModel ${topicSubModelEntry.sys.id} in the field ${subModelsFieldKey}`
975
- );
976
- data.fields = await addToRelationFields(
977
- data,
978
- subModelsFieldKey,
979
- topicSubModelEntry.sys.id,
980
- true
981
- );
982
- }
983
- }
984
- } else {
985
- log(
986
- `No topicSubModel found for product ${
987
- productDetails.code
988
- }: ${subModelsCodes.join(",")}`,
989
- "WARN"
990
- );
991
- }
992
- }
993
-
994
- // assets
995
- if (productDetails?.assets) {
996
- const pimAssetThumb = productDetails.assets.find(
997
- (asset) => asset?.assetType.code === "THUMB"
998
- );
999
-
1000
- // THUMB
1001
- if (pimAssetThumb?.url && pimAssetThumb?.md5) {
1002
- log(`Set THUMB`);
1003
- // THUMB WRAPPER IMGIX
1004
- const wrapperImgixID = pimAssetThumb.md5;
1005
- let wrapperImgix = await getEntryByID(
1006
- wrapperImgixID,
1007
- "wrapperImgix",
1008
- "sys,fields"
1009
- );
1010
- if (wrapperImgix) {
1011
- log(`wrapperImgix with id ${wrapperImgixID} already exists`);
1012
- const imgixBasename = basename(
1013
- wrapperImgix.fields.imgixData[defaultEnvironmentLocaleCode].url
1014
- );
1015
- const pimBasename = basename(pimAssetThumb.url);
1016
- if (imgixBasename !== pimBasename) {
1017
- log(`Update img url from ${imgixBasename} to ${pimBasename}`);
1018
- const newImgixUrl = getImgixPimUrlByOriginPath(
1019
- getOriginPathByPimUrl(pimAssetThumb.url)
1020
- );
1021
- wrapperImgix.fields.imgixData[defaultEnvironmentLocaleCode].url =
1022
- newImgixUrl;
1023
- wrapperImgix = await wrapperImgix.update();
1024
- if (wrapperImgix.isPublished()) {
1025
- wrapperImgix = await wrapperImgix.publish();
1026
- }
1027
-
1028
- log(`The new imgix url is: ${newImgixUrl}`);
1029
- } else {
1030
- log(`wrapperImgix basename matched`);
1031
- }
1032
- } else {
1033
- log(
1034
- `Add thumbnail imgix wrapper with id ${wrapperImgixID} to Contentful`
1035
- );
1036
- const altText: any = getPimTranslations(pimAssetThumb, "title");
1037
- if (altText[defaultEnvironmentLocaleCode] === null) {
1038
- altText[defaultEnvironmentLocaleCode] = "Thumbnail";
1039
- }
1040
- const wrapperImgixAttributes = getDefaultWrapperImgixAttributesByPimUrl(
1041
- pimAssetThumb.url
1042
- );
1043
- if (wrapperImgixAttributes) {
1044
- const wrapperImgixFields: WrapperImageFields = {
1045
- internalName: `${pimAssetThumb?.assetType?.code}_${pimAssetThumb.md5}`,
1046
- imgixData: wrapperImgixAttributes,
1047
- altText,
1048
- };
1049
- wrapperImgix = await createWrapperImgix(
1050
- wrapperImgixID,
1051
- wrapperImgixFields
1052
- );
1053
- } else {
1054
- log(
1055
- `Unable to create wrapperimagix because the image was not found on imgix. Image URL: ${pimAssetThumb.url}`,
1056
- "WARN"
1057
- );
1058
- }
1059
- }
1060
-
1061
- if (wrapperImgix?.sys?.id) {
1062
- data.fields = await addToRelationFields(
1063
- data,
1064
- "thumbnailImgix",
1065
- wrapperImgix.sys.id
1066
- );
1067
- }
1068
- } else {
1069
- log(`No thumbnail found or md5 is null`, "WARN");
1070
- }
1071
-
1072
- // OTHER ASSETS
1073
- const pimOtherAssets = productDetails.assets.filter(
1074
- (asset) => asset?.assetType.code !== "THUMB"
1075
- );
1076
- if (pimOtherAssets.length) {
1077
- log(`Uploading ${pimOtherAssets.length} assets to S3`);
1078
- const assets = await getProductAssets(
1079
- pimOtherAssets as AssetsEntity[],
1080
- productDetails.code
1081
- );
1082
- if (assets) {
1083
- data.fields = await addFieldValue(data, "assets", assets);
1084
- }
1085
- } else {
1086
- log(`No other assets found`, "WARN");
1087
- }
1088
- }
1089
-
1090
- // lastPimSyncDate
1091
- data.fields = await addFieldValue(data, "lastPimSyncDate", getLocalISOTime());
1092
-
1093
- // designers
1094
- if (productDetails.designers) {
1095
- for (const designer of productDetails.designers) {
1096
- data.fields = await addDesignerData(data, designer, true);
1097
- }
1098
- } else {
1099
- log(`No designers found`, "WARN");
1100
- if (data.fields.designers?.[defaultEnvironmentLocaleCode]) {
1101
- log(`remove old designers relation`);
1102
- data.fields.designers = [];
1103
- }
1104
- }
1105
-
1106
- // autodescription
1107
- data.fields.autoDescription = await getTopicProductAutodescription(
1108
- data.fields
1109
- );
1110
-
1111
- // Destinations
1112
- if (productDetails?.destinations?.length) {
1113
- log(`set destinations`);
1114
- data.fields = await addFieldValue(
1115
- data,
1116
- "destinations",
1117
- productDetails.destinations.map((item) => item.code)
1118
- );
1119
- } else {
1120
- log(`destinations not found`, "WARN");
1121
- }
1122
-
1123
- // endpoint payload - used into setProductRelationships
1124
- const productEntryId = getTopicProductIdByCode(productDetails.code);
1125
- const { path, fileName } = getProductPayloadS3Details(productEntryId);
1126
- log(`Uploading "${fileName}" to S3 path "${path}"`);
1127
- const { Location } = await saveJsonToS3(pimDetails, fileName, path);
1128
- data.fields = await addFieldValue(data, "endpointPayload", Location);
1129
- log(`"${fileName}" uploaded to ${Location}`);
1130
-
1131
- return data;
1132
- };
1133
-
1134
- const getProductColourVariantsData = async (
1135
- topicProductColourVariantsCode: string,
1136
- productEntryId: string,
1137
- topicProductColourVariants: Entry | null
1138
- ) => {
1139
- const defaultEnvironmentLocaleCode = await getEnvironmentDefaultLocaleCode();
1140
- const data: CreateEntryProps = {
1141
- fields: {
1142
- code: {},
1143
- lastPimSyncDate: {},
1144
- },
1145
- };
1146
-
1147
- if (topicProductColourVariants?.fields) {
1148
- data.fields = topicProductColourVariants.fields;
1149
- }
1150
-
1151
- // code
1152
- data.fields.code[defaultEnvironmentLocaleCode] =
1153
- topicProductColourVariantsCode;
1154
-
1155
- // products
1156
- data.fields = await addToRelationFields(
1157
- data,
1158
- "products",
1159
- productEntryId,
1160
- true
1161
- );
1162
-
1163
- // lastPimSyncDate
1164
- data.fields.lastPimSyncDate[defaultEnvironmentLocaleCode] = getLocalISOTime();
1165
-
1166
- return data;
1167
- };
1168
-
1169
- const addProductColourVariants = async (
1170
- colourVariants: ColourVariant[],
1171
- productEntryId: string
1172
- ) => {
1173
- for (const colourVariant of colourVariants) {
1174
- const topicId = `PCV_${colourVariant.code}`;
1175
- let topicProductColourVariants: Entry = await getEntryByID(
1176
- topicId,
1177
- "topicProductColourVariants"
1178
- );
1179
- const data = await getProductColourVariantsData(
1180
- colourVariant.code,
1181
- productEntryId,
1182
- topicProductColourVariants
1183
- );
1184
- if (!topicProductColourVariants) {
1185
- log(`Create topicProductColourVariants with code ${topicId}`);
1186
- // Create new topicProductColourVariants
1187
- topicProductColourVariants = await createEntryWithId(
1188
- "topicProductColourVariants",
1189
- topicId,
1190
- data,
1191
- true
1192
- );
1193
- } else {
1194
- log(`Update topicProductColourVariants with code ${topicId}`);
1195
- // Update existing topicProductColourVariants
1196
- topicProductColourVariants = await updateEntry(
1197
- topicProductColourVariants,
1198
- data,
1199
- topicProductColourVariants.isPublished()
1200
- );
1201
- }
1202
- }
1203
- };
1204
-
1205
- /**
1206
- * Import product
1207
- * - name
1208
- * - code
1209
- * - status
1210
- * - categories
1211
- * - families
1212
- * - subfamilies
1213
- * - models
1214
- * - submodels
1215
- * - productLine
1216
- * - accessories
1217
- * - accessoryOf
1218
- * - bulbOf
1219
- * - sparepartOf
1220
- * - bulbs
1221
- * - spareparts
1222
- * - pimDetails
1223
- * - lastPimSyncDate
1224
- */
1225
- const addProduct = async (
1226
- productDetails: ProductDetails
1227
- ): Promise<Entry | boolean> => {
1228
- // Check that the title is set
1229
- const title = productDetails.webNaming || productDetails.name;
1230
- if (!title) {
1231
- log(
1232
- `Can't possible to import the product ${productDetails.code}, name and webNaming not found`
1233
- );
1234
- return false;
1235
- }
1236
-
1237
- log(`If exists get entry with code: ${productDetails.code}`);
1238
-
1239
- let productEntry: Entry = await getEntryByCode(
1240
- productDetails.code,
1241
- "topicProduct"
1242
- );
1243
-
1244
- const productData = await getProductData(productEntry, productDetails);
1245
-
1246
- let publishEntry = false;
1247
-
1248
- if (!productEntry) {
1249
- const productEntryId = getTopicProductIdByCode(productDetails.code);
1250
- log(`Create product with code ${productEntryId}`);
1251
- // Create new topicProduct
1252
- productEntry = await createEntryWithId(
1253
- "topicProduct",
1254
- productEntryId,
1255
- productData,
1256
- false
1257
- );
1258
- } else {
1259
- if (productEntry.isArchived()) {
1260
- log(`Unarchive product with code ${productDetails.code}`);
1261
- productEntry = await productEntry.unarchive();
1262
- }
1263
- log(`Update product with code ${productDetails.code}`);
1264
- productEntry = await updateEntry(
1265
- productEntry,
1266
- productData,
1267
- productEntry.isPublished()
1268
- );
1269
- publishEntry = productEntry?.isPublished();
1270
- }
1271
-
1272
- log(`Publish entry: ${publishEntry}`);
1273
-
1274
- // Create or update pageContent and page of the current topicProduct
1275
- await createOrUpdateProductPage(productEntry, !publishEntry);
1276
-
1277
- if (productDetails?.colourVariants) {
1278
- await addProductColourVariants(
1279
- productDetails.colourVariants,
1280
- productEntry.sys.id
1281
- );
1282
- }
1283
-
1284
- return productEntry;
1285
- };
1286
-
1287
- const validateImportProduct = (
1288
- productDetails: ProductDetails,
1289
- catalog: AvailableCatalogs,
1290
- familyCodeIn?: string[],
1291
- subFamilyCodeIn?: string[]
1292
- ) => {
1293
- // Validate catalog
1294
- if (!productDetails.currentCatalog?.catalogCode) {
1295
- log(
1296
- `The product ${productDetails.code} does not belong to the ${catalog} catalog or the catalog is not specified. Catalog code: ${productDetails.currentCatalog?.catalogCode}`,
1297
- "WARN"
1298
- );
1299
- return false;
1300
- }
1301
-
1302
- // Validate family
1303
- if (
1304
- familyCodeIn?.length &&
1305
- !familyCodeIn.includes(productDetails.currentCatalog?.familyCode as string)
1306
- ) {
1307
- log(
1308
- `The product ${
1309
- productDetails.code
1310
- } does not belong to any of the ${familyCodeIn.join(
1311
- ","
1312
- )} families or the family is not specified. Family code: ${
1313
- productDetails.currentCatalog?.familyCode
1314
- }`,
1315
- "WARN"
1316
- );
1317
- return false;
1318
- }
1319
-
1320
- // Validate subfamily
1321
- if (
1322
- subFamilyCodeIn?.length &&
1323
- !subFamilyCodeIn.includes(
1324
- productDetails.currentCatalog?.subFamilyCode as string
1325
- )
1326
- ) {
1327
- log(
1328
- `The product ${
1329
- productDetails.code
1330
- } does not belong to any of the ${subFamilyCodeIn.join(
1331
- ","
1332
- )} subFamilies or the subFamily is not specified. SubFamily code: ${
1333
- productDetails.currentCatalog?.subFamilyCode
1334
- }`,
1335
- "WARN"
1336
- );
1337
- return false;
1338
- }
1339
-
1340
- return true;
1341
- };
1342
-
1343
- /**
1344
- * Import product
1345
- *
1346
- * create/update topicProduct
1347
- * - name
1348
- * - code
1349
- * - pimDetails
1350
- * - status
1351
- * - catalogs
1352
- * - categories
1353
- * - subFamilies
1354
- * - productLine
1355
- * - lastPimSyncDate
1356
- *
1357
- * @param productDetails
1358
- * @param catalog
1359
- * @returns
1360
- */
1361
- export const importProduct = async (
1362
- productDetails: ProductDetails,
1363
- catalog: AvailableCatalogs,
1364
- familyCodeIn?: string[],
1365
- subFamilyCodeIn?: string[]
1366
- ): Promise<boolean> => {
1367
- productDetails.currentCatalog = productDetails.catalogs?.find(
1368
- (itemCatalog) => itemCatalog.catalogCode === catalog
1369
- );
1370
-
1371
- if (
1372
- !validateImportProduct(
1373
- productDetails,
1374
- catalog,
1375
- familyCodeIn,
1376
- subFamilyCodeIn
1377
- )
1378
- ) {
1379
- return false;
1380
- }
1381
-
1382
- log(`Import product ${productDetails.code}`, "INFO");
1383
-
1384
- const isTermsToAddCode = await isTermsToAdd(productDetails, catalog);
1385
- if (isTermsToAddCode) {
1386
- return false;
1387
- }
1388
-
1389
- if (
1390
- (productDetails.visibleToWeb === true ||
1391
- productDetails.code === "0000000-TEST") &&
1392
- productDetails.destinations?.filter((item) =>
1393
- item.code.includes("PROFESSIONAL_")
1394
- ).length
1395
- ) {
1396
- await addProduct(productDetails);
1397
- return true;
1398
- } else {
1399
- await notVisibleToWebProduct(productDetails.code);
1400
- const destinations = productDetails.destinations
1401
- ?.map((item) => item.code)
1402
- .join(", ");
1403
-
1404
- log(
1405
- `Product not to be imported: ${productDetails.code} - visibleToWeb = ${productDetails.visibleToWeb} - destinations = [${destinations}]`
1406
- );
1407
- return false;
1408
- }
1409
- };
1410
-
1411
- export const setProductRelationships = async (
1412
- code: string,
1413
- fieldKey: AvailableRelationFieldKeys | null = null
1414
- ) => {
1415
- log(`setProductRelationships - code: ${code} fieldKey: ${fieldKey}`, "INFO");
1416
-
1417
- const fieldKeys: AvailableRelationFieldKeys[] = [
1418
- "accessories",
1419
- "accessoryOf",
1420
- "bulbOf",
1421
- "sparepartOf",
1422
- "bulbs",
1423
- "spareparts",
1424
- ];
1425
-
1426
- if (!fieldKey) {
1427
- log(
1428
- `The fieldKey parameter is empty so all fields will be imported: ${fieldKeys.join(
1429
- ","
1430
- )} `
1431
- );
1432
- }
1433
-
1434
- const currentFieldKeys = fieldKey ? [fieldKey] : fieldKeys;
1435
- let productEntry = await getEntryByCode(code, "topicProduct");
1436
- if (!productEntry) {
1437
- log(`Product with code ${code} not found`, "WARN");
1438
- } else if (productEntry.isArchived()) {
1439
- log(`Product with code ${code} is archived`, "WARN");
1440
- } else if (!productEntry.isArchived()) {
1441
- const { path, fileName } = getProductPayloadS3Details(productEntry.sys.id);
1442
- log(`Get payload from ${path}${fileName} S3 path`);
1443
- const productDetails = await getFileFromS3(`${path}${fileName}`);
1444
- if (productDetails) {
1445
- const defaultEnvironmentLocaleCode =
1446
- await getEnvironmentDefaultLocaleCode();
1447
- let update = false;
1448
- let fieldKeysCount = 0;
1449
- for (const currentFieldKey of currentFieldKeys) {
1450
- log(`Set ${currentFieldKey} relations to product with code ${code}`);
1451
- const fieldValues: ProductRelation[] = productDetails[currentFieldKey];
1452
-
1453
- if (fieldValues) {
1454
- const relationships = [];
1455
- const producRelationCodes = fieldValues.map((fieldValue) => {
1456
- return fieldValue.code;
1457
- });
1458
-
1459
- const entries = await getAllEntriesByCodes(
1460
- producRelationCodes,
1461
- "topicProduct",
1462
- "sys,fields.code"
1463
- );
1464
-
1465
- for (const fieldValue of fieldValues) {
1466
- const entry = entries.find(
1467
- (currentEntry) =>
1468
- currentEntry.fields.code[defaultEnvironmentLocaleCode] ===
1469
- fieldValue.code
1470
- );
1471
- if (entry) {
1472
- relationships.push({
1473
- quantity: fieldValue.quantity || "",
1474
- typeCode: fieldValue.typeCode || "",
1475
- typeLabel: fieldValue.typeLabel || "",
1476
- entryId: entry.sys.id,
1477
- });
1478
- } else {
1479
- log(
1480
- `The product with ${fieldValue.code} code was not found, it cannot be associated with the ${currentFieldKey} field of product ${code}`
1481
- );
1482
- }
1483
- }
1484
- const prevItemsCount =
1485
- productEntry?.fields[currentFieldKey]?.length || 0;
1486
- if (relationships.length || prevItemsCount > 0) {
1487
- if (!relationships.length && prevItemsCount > 0) {
1488
- log(
1489
- `No product relationships found of the field ${currentFieldKey} for the product ${code}, i remove ${prevItemsCount} pre-existing relationships`
1490
- );
1491
- } else {
1492
- log(
1493
- `Founded ${relationships.length} relationships of ${producRelationCodes.length} PIM relationships for the field ${currentFieldKey} of product ${code}`
1494
- );
1495
- }
1496
- productEntry.fields[currentFieldKey] = {};
1497
- productEntry.fields[currentFieldKey][defaultEnvironmentLocaleCode] =
1498
- relationships;
1499
- update = true;
1500
- } else {
1501
- log(
1502
- `No product relationships found of the field ${currentFieldKey} for the product ${code}`
1503
- );
1504
- }
1505
-
1506
- if (++fieldKeysCount % 7 === 0) {
1507
- await sleep(2000, true);
1508
- }
1509
- } else {
1510
- log(`No field ${currentFieldKey} found for the product ${code}`);
1511
- }
1512
- }
1513
-
1514
- if (update) {
1515
- try {
1516
- productEntry = await productEntry.update();
1517
- log(`Updated ${code} product changes`);
1518
- if (productEntry.isPublished()) {
1519
- try {
1520
- productEntry = await productEntry.publish();
1521
- log(`Published ${code} product`);
1522
- } catch (err: any) {
1523
- const message = `setProductRelationships - Cannot publish entry. ${code}`;
1524
- await notify(message, false);
1525
- log(message);
1526
- log(err);
1527
- }
1528
- }
1529
- } catch (err: any) {
1530
- const message = `setProductRelationships - Cannot update entry. ${code}`;
1531
- await notify(message, false);
1532
- log(message);
1533
- log(err);
1534
- }
1535
- }
1536
- } else {
1537
- log(
1538
- `${productEntry.sys.id} product payload was not found on S3. Relationships cannot be set.`,
1539
- "WARN"
1540
- );
1541
- }
1542
- }
1543
- };
1544
-
1545
- /**
1546
- * Set the product relationships
1547
- *
1548
- * TODO: È uno dei punti critici dell'import, in quanto dovento interrogare
1549
- * l'endpoint /products?catalog&lastModified dobbiamo obbligatoriamente scorrere
1550
- * tutti i prodotti restituiti anche se non interessano.
1551
- * Potremmo passare la data in cui l'import inizia e ottenere a questo punto
1552
- * tutti i topicProduct, del catalogo in questione, che hanno il campo lastPimSyncDate >= a quello di inizio import
1553
- * di contro, facendo così aumenteremmo le chiamate fatte a contentful
1554
- *
1555
- * @param catalog
1556
- * @param lastModified 20210527T00:00:01
1557
- * @param offset
1558
- * @param limit
1559
- * @param s3FilePath pim/2021-05-27/all-products/all-products-ARCHITECTURAL-20200101T00:00:01.json
1560
- * @returns
1561
- */
1562
- export const setProductsRelationships = async (
1563
- catalog: AvailableCatalogs,
1564
- lastModified: string,
1565
- fieldKey: AvailableRelationFieldKeys | null,
1566
- offset: number = 0,
1567
- limit: number = 150,
1568
- s3FilePath: string = ""
1569
- ) => {
1570
- const timeStart = new Date();
1571
- log(
1572
- `setProductsRelationships - catalog: ${catalog} lastModified: ${lastModified} fieldKey: ${fieldKey} offset: ${offset} limit: ${limit} s3FilePath: ${s3FilePath}`,
1573
- "INFO"
1574
- );
1575
-
1576
- if (!s3FilePath) {
1577
- const s3Path: string = await saveAllProductsToS3(catalog, lastModified);
1578
-
1579
- const tEnd = new Date();
1580
- const secs = secondBetweenTwoDate(timeStart, tEnd);
1581
- log(`Request time: ${secs} seconds`);
1582
-
1583
- return {
1584
- offset: Number(offset),
1585
- limit: Number(limit),
1586
- completed: false,
1587
- s3FilePath: s3Path,
1588
- };
1589
- }
1590
-
1591
- const JSONData: AllProductsEntry[] = await getFileFromS3(s3FilePath);
1592
- const total: number = JSONData.length;
1593
-
1594
- log(`${total} products founded`);
1595
-
1596
- let count: number = 0;
1597
- let updated: number = 0;
1598
- let current: number = 0;
1599
- for (const product of JSONData) {
1600
- if (offset <= count || limit === -1) {
1601
- log(`${count + 1} of ${JSONData.length}`);
1602
- await setProductRelationships(product.code, fieldKey);
1603
- updated++;
1604
-
1605
- if (serverUtils) {
1606
- serverUtils.log(product.code);
1607
- const currentTotal =
1608
- JSONData.length > limit && limit !== -1 ? limit : JSONData.length;
1609
- const progress = Math.floor((++current / currentTotal) * 100);
1610
- serverUtils.updateProgress(progress);
1611
- }
1612
-
1613
- if (updated % 7 === 0) {
1614
- await sleep(500);
1615
- }
1616
-
1617
- if (limit !== -1 && count + 1 - offset >= limit) {
1618
- break;
1619
- }
1620
- }
1621
- count++;
1622
- }
1623
-
1624
- const timeEnd = new Date();
1625
- const seconds = secondBetweenTwoDate(timeStart, timeEnd);
1626
- log(`Request time: ${seconds} seconds`);
1627
-
1628
- if (serverUtils) {
1629
- serverUtils.updateProgress(100);
1630
- }
1631
-
1632
- return {
1633
- offset: Number(offset) + Number(limit),
1634
- limit: Number(limit),
1635
- completed: limit === -1 || limit > updated,
1636
- s3FilePath,
1637
- total: JSONData.length,
1638
- };
1639
- };
1640
-
1641
- const removeProductFromAllOfRelationFields = async (
1642
- productCode: string,
1643
- fieldKey: string,
1644
- codes: string[]
1645
- ) => {
1646
- const fieldKeysOf = {
1647
- accessories: "accessoryOf",
1648
- spareparts: "sparepartOf",
1649
- bulb: "bulbOf",
1650
- };
1651
- const fieldKeyOf =
1652
- fieldKey in fieldKeysOf
1653
- ? fieldKeysOf[fieldKey as keyof typeof fieldKeysOf]
1654
- : "";
1655
-
1656
- if (!fieldKeyOf) {
1657
- log(`The fieldKey ${fieldKey} is not valid`, "WARN");
1658
- return;
1659
- }
1660
- const productEntries = await getAllEntriesByCodes(
1661
- codes,
1662
- "topicProduct",
1663
- "sys,fields",
1664
- "fields.code"
1665
- );
1666
-
1667
- log(
1668
- `Remove ${fieldKeyOf} relation from ${productEntries.length} topicProduct`
1669
- );
1670
- for (let productEntry of productEntries) {
1671
- if (productEntry.isArchived()) {
1672
- log(
1673
- `Can't remove the ${fieldKeyOf} from ${productEntry.sys.id} because it is archived.`,
1674
- "WARN"
1675
- );
1676
- } else {
1677
- log(
1678
- `Removing ${productCode} from the ${fieldKeyOf} of the product ${productEntry.sys.id}...`
1679
- );
1680
- productEntry.fields = await removeFromFieldObject(
1681
- productEntry,
1682
- fieldKeyOf,
1683
- productCode
1684
- );
1685
- try {
1686
- log(`update ${productEntry.sys.id}`);
1687
- productEntry = await productEntry.update();
1688
- if (productEntry.isPublished()) {
1689
- try {
1690
- productEntry = await productEntry.publish();
1691
- } catch (err: any) {
1692
- log(`Cannot publish entry ${productEntry.sys.id}.`);
1693
- log(err);
1694
- }
1695
- }
1696
- } catch (err: any) {
1697
- log(`Cannot update entry ${productEntry.sys.id}.`);
1698
- log(err);
1699
- }
1700
- }
1701
- }
1702
- };
1703
-
1704
- /**
1705
- * Get all product entries of a specific catalog
1706
- *
1707
- * @param catalog
1708
- * @returns
1709
- */
1710
- export const getAllProductEntriesByCatalog = async (
1711
- catalog: AvailableCatalogs,
1712
- limit: number = 100,
1713
- select: string = ""
1714
- ): Promise<Entry[]> => {
1715
- log(`getAllProductEntriesByCatalog - catalog: ${catalog}`, "INFO");
1716
- const env = await getEnvironment();
1717
- const defEnvLocaleCode = await getEnvironmentDefaultLocaleCode();
1718
- let allItems: Entry[] = [];
1719
- let othersPagesToFetch = false;
1720
- let skip = 0;
1721
- let count = 0;
1722
- do {
1723
- const { items, total } = await env.getEntries({
1724
- content_type: "topicProduct",
1725
- "fields.catalogs.sys.id": catalog,
1726
- limit,
1727
- skip,
1728
- locale: defEnvLocaleCode,
1729
- include: 0,
1730
- select,
1731
- });
1732
-
1733
- allItems = [...allItems, ...(items || [])];
1734
-
1735
- log(`${allItems.length} topicProduct founded of ${total}`);
1736
-
1737
- if (total && allItems.length < total) {
1738
- othersPagesToFetch = true;
1739
- skip += limit;
1740
- if (++count % 7 === 0) {
1741
- await sleep(200);
1742
- }
1743
- } else {
1744
- othersPagesToFetch = false;
1745
- }
1746
- } while (othersPagesToFetch);
1747
-
1748
- log(`${allItems.length} topicProduct founded`);
1749
-
1750
- return allItems;
1751
- };
1752
-
1753
- const productAudit = async (
1754
- audit: Audit,
1755
- productEntries: Entry[],
1756
- catalog: AvailableCatalogs,
1757
- defaultEnvironmentLocaleCode: string,
1758
- current: number,
1759
- allAudit: Audit[],
1760
- productPageEntries: Entry[]
1761
- ) => {
1762
- log(`Search product entry with id ${audit.product}...`);
1763
- let productEntry = productEntries.find(
1764
- (currentEntry) =>
1765
- currentEntry?.fields?.code?.[defaultEnvironmentLocaleCode] ===
1766
- audit.product
1767
- );
1768
-
1769
- if (!productEntry) {
1770
- let logMessage = "";
1771
- if (catalog) {
1772
- logMessage = `The ${audit.product} product was not found in the CMS with catalog ${catalog}`;
1773
- } else {
1774
- logMessage = `The ${audit.product} product was not found in the CMS`;
1775
- }
1776
- log(logMessage, "WARN");
1777
-
1778
- if (serverUtils) {
1779
- serverUtils.log(logMessage);
1780
- const progress = Math.floor((++current / allAudit.length) * 100);
1781
- serverUtils.updateProgress(progress);
1782
- }
1783
- return { current, continue: true };
1784
- }
1785
-
1786
- log(`Founded product with id ${productEntry.sys.id}`);
1787
-
1788
- const pageEntryFromId = getProductPageIdByCode(audit.product);
1789
- log(`Search product page entry with id ${pageEntryFromId}...`);
1790
- let pageEntryFrom = productPageEntries.find(
1791
- (currentEntry) => currentEntry.sys.id === pageEntryFromId
1792
- );
1793
-
1794
- if (pageEntryFrom) {
1795
- log(`Founded product page with id ${pageEntryFrom.sys.id}`);
1796
- } else {
1797
- log(`Product page with id ${pageEntryFromId} not found`, "WARN");
1798
- }
1799
-
1800
- log(`Get product catalogs...`);
1801
- const productCatalogs: AvailableCatalogs[] = productEntry?.fields?.catalogs?.[
1802
- defaultEnvironmentLocaleCode
1803
- ].map((entryCatalog: FieldItem) => {
1804
- return entryCatalog.sys.id;
1805
- });
1806
-
1807
- if (catalog && !productCatalogs.includes(catalog)) {
1808
- log(`Product ${audit.product} does not belong to the ${catalog} catalog`);
1809
- } else if (["PRODUCT_UNPUBLISH", "PRODUCT_WEBOFF"].includes(audit.what)) {
1810
- log(`Set the product status as archive...`);
1811
- // Set the product status as archive
1812
- productEntry = await archiveEntry(productEntry, true);
1813
- if (!pageEntryFrom) {
1814
- log(`${pageEntryFromId} page from not found`);
1815
- } else if (pageEntryFrom.isArchived()) {
1816
- log(
1817
- `Can't create redirect ${audit.product} to ${audit.upgradeProduct} because the page ${pageEntryFrom.sys.id} is archived.`,
1818
- "WARN"
1819
- );
1820
- } else if (pageEntryFrom?.fields) {
1821
- if (audit.upgradeProduct && audit.upgradeProduct !== "0") {
1822
- log(
1823
- `Creating redirect from ${audit.product} to ${audit.upgradeProduct}`
1824
- );
1825
- const pageEntryToId = getProductPageIdByCode(audit.upgradeProduct);
1826
- const pageEntryTo = await getEntryByID(pageEntryToId, "page", "sys.id");
1827
-
1828
- if (pageEntryTo) {
1829
- // Save redirect
1830
- pageEntryFrom.fields = await addToRelationFields(
1831
- pageEntryFrom,
1832
- "redirectTo",
1833
- pageEntryTo.sys.id
1834
- );
1835
- pageEntryFrom = await pageEntryFrom.update();
1836
- } else {
1837
- log(
1838
- `Can't create redirect ${audit.product} to ${audit.upgradeProduct} because the page ${pageEntryToId} not found.`,
1839
- "WARN"
1840
- );
1841
- }
1842
- }
1843
-
1844
- pageEntryFrom = await archiveEntry(pageEntryFrom);
1845
- }
1846
- } else if (
1847
- audit.what === "REMOVE_PRODUCT_RELATIONS" &&
1848
- !productEntry.isArchived()
1849
- ) {
1850
- log(`Remove product relations...`);
1851
- if (productEntry.isUpdated()) {
1852
- try {
1853
- log(`Publish existing changes of entry ${productEntry.sys.id}.`);
1854
- productEntry = await productEntry.publish();
1855
- } catch (err: any) {
1856
- log(`Cannot publish changes of entry ${productEntry.sys.id}.`);
1857
- log(err);
1858
- }
1859
- }
1860
- if (audit?.catalogs) {
1861
- for (const item of audit?.catalogs) {
1862
- if (!item?.where) {
1863
- log(
1864
- `catalogs.where field not exists. Product: ${audit.product} `,
1865
- "WARN"
1866
- );
1867
- } else {
1868
- let edit = false;
1869
- if (item?.catalogCode) {
1870
- productEntry.fields = await removeFromRelationFields(
1871
- productEntry,
1872
- "catalogs",
1873
- item.catalogCode,
1874
- true
1875
- );
1876
- log(`edit catalogs`);
1877
- edit = true;
1878
- }
1879
- if (item?.categoryCode) {
1880
- const categoriesFieldKey =
1881
- "categories" + capitalizeFirstLetter(item.where);
1882
- productEntry.fields = await removeFromRelationFields(
1883
- productEntry,
1884
- categoriesFieldKey,
1885
- item.categoryCode,
1886
- true
1887
- );
1888
- log(`edit ${categoriesFieldKey}`);
1889
- edit = true;
1890
- }
1891
- if (item?.subfamilyCode) {
1892
- const subFamiliesFieldKey =
1893
- "subFamilies" + capitalizeFirstLetter(item.where);
1894
- productEntry.fields = await removeFromRelationFields(
1895
- productEntry,
1896
- subFamiliesFieldKey,
1897
- item.subfamilyCode,
1898
- true
1899
- );
1900
- log(`edit ${subFamiliesFieldKey}`);
1901
- edit = true;
1902
- }
1903
- if (item?.models) {
1904
- const modelsFieldKey = "models" + capitalizeFirstLetter(item.where);
1905
- productEntry.fields = await removeFromRelationFields(
1906
- productEntry,
1907
- modelsFieldKey,
1908
- item.models,
1909
- true
1910
- );
1911
- log(`edit ${modelsFieldKey}`);
1912
- edit = true;
1913
- }
1914
- if (item?.subModels) {
1915
- const subModelsFieldKey =
1916
- "subModels" + capitalizeFirstLetter(item.where);
1917
- productEntry.fields = await removeFromRelationFields(
1918
- productEntry,
1919
- subModelsFieldKey,
1920
- item.subModels,
1921
- true
1922
- );
1923
- log(`edit ${subModelsFieldKey}`);
1924
- edit = true;
1925
- }
1926
-
1927
- const objectFieldsRelations: any = {
1928
- ACCESSORIES: "accessories",
1929
- SPARE_PARTS: "spareparts",
1930
- BULBS: "bulbs",
1931
- };
1932
-
1933
- for (const objectFieldsRelationKey of Object.keys(
1934
- objectFieldsRelations
1935
- )) {
1936
- if (item.where === objectFieldsRelationKey) {
1937
- log(`Remove ${objectFieldsRelationKey} relations`);
1938
- const codes = item.codes?.split(",") ?? [];
1939
- if (codes.length) {
1940
- const fieldKey = objectFieldsRelations[objectFieldsRelationKey];
1941
- const lengthBefore =
1942
- productEntry.fields?.[fieldKey]?.[
1943
- defaultEnvironmentLocaleCode
1944
- ].length;
1945
-
1946
- // Remove from the main product field
1947
- productEntry.fields = await removeFromFieldObject(
1948
- productEntry,
1949
- fieldKey,
1950
- codes
1951
- );
1952
- // Remove from the codes of field
1953
- await removeProductFromAllOfRelationFields(
1954
- productEntry.sys.id,
1955
- fieldKey,
1956
- codes
1957
- );
1958
-
1959
- const lengthAfter =
1960
- productEntry.fields?.[fieldKey]?.[
1961
- defaultEnvironmentLocaleCode
1962
- ].length;
1963
- if (lengthBefore !== lengthAfter) {
1964
- log(
1965
- `edit field ${fieldKey} lengthBefore: ${lengthBefore} lengthAfter: ${lengthAfter}`
1966
- );
1967
- edit = true;
1968
- } else {
1969
- log(`No valid ${objectFieldsRelationKey} to remove found`);
1970
- }
1971
- }
1972
- }
1973
- }
1974
-
1975
- if (item.where === "DESIGNERS" && item?.codes) {
1976
- const lengthBefore =
1977
- productEntry.fields?.designer?.[defaultEnvironmentLocaleCode]
1978
- .length;
1979
- const designers = item.codes.split(",");
1980
- for (const designer of designers) {
1981
- log(
1982
- `Remove ${designer} designer to ${productEntry.sys.id} product if exists`
1983
- );
1984
- productEntry.fields = await removeFromRelationFields(
1985
- productEntry,
1986
- "designer",
1987
- designer,
1988
- false
1989
- );
1990
- }
1991
-
1992
- if (
1993
- lengthBefore !==
1994
- productEntry.fields?.designer?.[defaultEnvironmentLocaleCode]
1995
- .length
1996
- ) {
1997
- log(`edit designer`);
1998
- edit = true;
1999
- } else {
2000
- log(`No valid designer to remove found`);
2001
- }
2002
- }
2003
-
2004
- if (edit) {
2005
- // lastPimSyncDate
2006
- productEntry.fields = await addFieldValue(
2007
- productEntry,
2008
- "lastPimSyncDate",
2009
- getLocalISOTime()
2010
- );
2011
- try {
2012
- log(`update ${productEntry.sys.id}`);
2013
- productEntry = await productEntry.update();
2014
- if (productEntry.isPublished()) {
2015
- try {
2016
- productEntry = await productEntry.publish();
2017
- } catch (err: any) {
2018
- log(`Cannot publish entry ${productEntry.sys.id}.`);
2019
- log(err);
2020
- }
2021
- }
2022
- } catch (err: any) {
2023
- log(`Cannot update entry ${productEntry.sys.id}.`);
2024
- log(err);
2025
- }
2026
- } else {
2027
- log(`No valid editable criteria found`);
2028
- console.log(productEntry.sys.id, "audit", audit);
2029
- }
2030
- }
2031
- }
2032
- } else {
2033
- log(
2034
- `No catalogs field found in the audit ${audit.product} product`,
2035
- "WARN"
2036
- );
2037
- }
2038
- } else {
2039
- log(`It has not yet been defined how to process the state ${audit.what}`);
2040
- }
2041
-
2042
- return { current, continue: false };
2043
- };
2044
-
2045
- const familyAudit = async (
2046
- audit: Audit,
2047
- familyEntries: Entry[],
2048
- catalog: AvailableCatalogs,
2049
- defaultEnvironmentLocaleCode: string,
2050
- current: number,
2051
- allAudit: Audit[]
2052
- ) => {
2053
- log(`Search family entry with id ${audit.product}...`);
2054
- let familyEntry = familyEntries.find(
2055
- (currentEntry) =>
2056
- currentEntry?.fields?.code?.[defaultEnvironmentLocaleCode] ===
2057
- audit.product
2058
- );
2059
-
2060
- if (!familyEntry) {
2061
- let logMessage = "";
2062
- if (catalog) {
2063
- logMessage = `The ${audit.product} family was not found in the CMS with catalog ${catalog}`;
2064
- } else {
2065
- logMessage = `The ${audit.product} family was not found in the CMS`;
2066
- }
2067
- log(logMessage, "WARN");
2068
-
2069
- if (serverUtils) {
2070
- serverUtils.log(logMessage);
2071
- const progress = Math.floor((++current / allAudit.length) * 100);
2072
- serverUtils.updateProgress(progress);
2073
- }
2074
- return { current, continue: true };
2075
- }
2076
-
2077
- log(`Founded family with id ${familyEntry.sys.id}`);
2078
-
2079
- log(`Get family catalogs...`);
2080
- const familyCatalogs: AvailableCatalogs[] = familyEntry?.fields?.catalogs?.[
2081
- defaultEnvironmentLocaleCode
2082
- ].map((entryCatalog: FieldItem) => {
2083
- return entryCatalog.sys.id;
2084
- });
2085
-
2086
- if (catalog && !familyCatalogs.includes(catalog)) {
2087
- log(`Family ${audit.product} does not belong to the ${catalog} catalog`);
2088
- } else if (audit.what === "REMOVE_FAMILY_RELATIONS") {
2089
- for (const item of audit?.catalogs) {
2090
- if (!item?.where) {
2091
- log(
2092
- `catalogs.where field not exists. Family: ${audit.product} `,
2093
- "WARN"
2094
- );
2095
- } else {
2096
- if (item.where === "DESIGNERS" && item?.codes) {
2097
- const designers = item.codes.split(",");
2098
- for (const designer of designers) {
2099
- log(
2100
- `Remove ${designer} designer to ${familyEntry.sys.id} family if exists`
2101
- );
2102
- familyEntry.fields = await removeFromRelationFields(
2103
- familyEntry,
2104
- "designer",
2105
- designer,
2106
- false
2107
- );
2108
- }
2109
- familyEntry = await familyEntry.update();
2110
- }
2111
- }
2112
- }
2113
- } else {
2114
- log(`It has not yet been defined how to process the state ${audit.what}`);
2115
- }
2116
-
2117
- return { current, continue: false };
2118
- };
2119
-
2120
- const subFamilyAudit = async (
2121
- audit: Audit,
2122
- subfamilyEntries: Entry[],
2123
- catalog: AvailableCatalogs,
2124
- defaultEnvironmentLocaleCode: string,
2125
- current: number,
2126
- allAudit: Audit[]
2127
- ) => {
2128
- log(`Search subFamily entry with id ${audit.product}...`);
2129
- let subFamilyEntry = subfamilyEntries.find(
2130
- (currentEntry) =>
2131
- currentEntry?.fields?.code?.[defaultEnvironmentLocaleCode] ===
2132
- audit.product
2133
- );
2134
-
2135
- if (!subFamilyEntry) {
2136
- let logMessage = "";
2137
- if (catalog) {
2138
- logMessage = `The ${audit.product} subFamily was not found in the CMS with catalog ${catalog}`;
2139
- } else {
2140
- logMessage = `The ${audit.product} subFamily was not found in the CMS`;
2141
- }
2142
- log(logMessage, "WARN");
2143
-
2144
- if (serverUtils) {
2145
- serverUtils.log(logMessage);
2146
- const progress = Math.floor((++current / allAudit.length) * 100);
2147
- serverUtils.updateProgress(progress);
2148
- }
2149
- return { current, continue: true };
2150
- }
2151
-
2152
- log(`Founded subFamily with id ${subFamilyEntry.sys.id}`);
2153
-
2154
- log(`Get subFamily catalogs...`);
2155
- const subFamilyCatalog: AvailableCatalogs =
2156
- subFamilyEntry?.fields?.catalog?.[defaultEnvironmentLocaleCode].sys.id;
2157
-
2158
- if (catalog && subFamilyCatalog !== catalog) {
2159
- log(`SubFamily ${audit.product} does not belong to the ${catalog} catalog`);
2160
- } else if (audit.what === "REMOVE_SUBFAMILY_RELATIONS") {
2161
- for (const item of audit?.catalogs) {
2162
- if (!item?.where) {
2163
- log(
2164
- `catalogs.where field not exists. SubFamily: ${audit.product} `,
2165
- "WARN"
2166
- );
2167
- } else {
2168
- if (item.where === "DESIGNERS" && item?.codes) {
2169
- const designers = item.codes.split(",");
2170
- for (const designer of designers) {
2171
- log(
2172
- `Remove ${designer} designer to ${subFamilyEntry.sys.id} subFamily if exists`
2173
- );
2174
- subFamilyEntry.fields = await removeFromRelationFields(
2175
- subFamilyEntry,
2176
- "designer",
2177
- designer,
2178
- false
2179
- );
2180
- }
2181
- subFamilyEntry = await subFamilyEntry.update();
2182
- }
2183
- }
2184
- }
2185
- } else {
2186
- log(`It has not yet been defined how to process the state ${audit.what}`);
2187
- }
2188
-
2189
- return { current, continue: false };
2190
- };
2191
-
2192
- /**
2193
- *
2194
- * Audit - Checks if there are products to publish or unpublish
2195
- *
2196
- * @param {string} lastModified The last modified data. Format: 20200426T07:50:00 - yearmonthdayThour:minute:second
2197
- * @param {string} catalog
2198
- */
2199
- export const audit = async (
2200
- lastModified: string,
2201
- catalog: AvailableCatalogs,
2202
- offset: number = 0,
2203
- limit: number = 150,
2204
- s3FilePath: string = ""
2205
- ) => {
2206
- offset = Number(offset);
2207
- limit = Number(limit);
2208
- const timeStart = new Date();
2209
- log(`audit - lastModified: ${lastModified} catalog: ${catalog}`, "INFO");
2210
-
2211
- // if not exists save data to s3
2212
- if (!s3FilePath) {
2213
- const allAudit = await getAudit(lastModified);
2214
- if (!allAudit) {
2215
- log(`No audits were found to process for the date ${lastModified}`);
2216
- return {
2217
- offset,
2218
- limit,
2219
- completed: true,
2220
- s3FilePath: "",
2221
- total: 0,
2222
- processedEntries: 0,
2223
- };
2224
- }
2225
-
2226
- const filename = `${lastModified}-all-audit.json`;
2227
- const path = `audit`;
2228
- await saveJsonToS3(allAudit, filename, path);
2229
- const s3Path = `${path}/${filename}`;
2230
-
2231
- if (serverUtils) {
2232
- serverUtils.log(`Saved s3FilePath: ${s3Path}`);
2233
- serverUtils.updateProgress(100);
2234
- }
2235
-
2236
- return {
2237
- offset: Number(offset),
2238
- limit: Number(limit),
2239
- completed: false,
2240
- s3FilePath: s3Path,
2241
- total: allAudit.length,
2242
- processedEntries: 0,
2243
- };
2244
- }
2245
-
2246
- // get data from s3
2247
- log(`Get audit details from ${s3FilePath}`);
2248
- let allAudit: Audit[] = await getFileFromS3(s3FilePath);
2249
- const total: number = allAudit.length;
2250
- allAudit = allAudit.slice(offset, offset + limit);
2251
- log(`Founded ${allAudit.length} items`);
2252
-
2253
- if (allAudit) {
2254
- const defaultEnvironmentLocaleCode =
2255
- await getEnvironmentDefaultLocaleCode();
2256
-
2257
- const productAuditWhat = [
2258
- "PRODUCT_UNPUBLISH",
2259
- "PRODUCT_WEBOFF",
2260
- "REMOVE_PRODUCT_RELATIONS",
2261
- ];
2262
- const productCodes = allAudit
2263
- .filter((item) => productAuditWhat.includes(item.what))
2264
- .map((audit) => audit.product);
2265
- const familyCodes = allAudit
2266
- .filter((item) => item.what === "REMOVE_FAMILY_RELATIONS")
2267
- .map((audit) => audit.product);
2268
- const subFamilyCodes = allAudit
2269
- .filter((item) => item.what === "REMOVE_SUBFAMILY_RELATIONS")
2270
- .map((audit) => audit.product);
2271
- const otherFilters = [];
2272
- if (catalog) {
2273
- otherFilters.push({ key: "fields.catalogs.sys.id[in]", value: catalog });
2274
- }
2275
- log(`Get ${productCodes.length} product entry from Contentful`);
2276
- const productEntries = await getAllEntriesByCodes(
2277
- productCodes,
2278
- "topicProduct",
2279
- "sys,fields",
2280
- "fields.code",
2281
- otherFilters
2282
- );
2283
- log(`Founded ${productEntries.length} topicProduct`);
2284
-
2285
- let familyEntries: Entry[] = [];
2286
- if (familyCodes.length) {
2287
- familyEntries = await getAllEntriesByCodes(
2288
- familyCodes,
2289
- "topicFamily",
2290
- "sys,fields",
2291
- "fields.code",
2292
- otherFilters
2293
- );
2294
- }
2295
- log(`Founded ${familyEntries.length} topicFamily`);
2296
-
2297
- let subFamilyEntries: Entry[] = [];
2298
- if (subFamilyCodes.length) {
2299
- subFamilyEntries = await getAllEntriesByCodes(
2300
- subFamilyCodes,
2301
- "topicSubFamily",
2302
- "sys,fields",
2303
- "fields.code",
2304
- otherFilters
2305
- );
2306
- }
2307
- log(`Founded ${subFamilyEntries.length} topicSubFamily`);
2308
-
2309
- if (
2310
- !productEntries.length &&
2311
- !familyEntries.length &&
2312
- !subFamilyEntries.length
2313
- ) {
2314
- log(
2315
- `No items found between offset: ${offset} and limit: ${limit}. Total: ${total}`
2316
- );
2317
- const nextOffset = offset + limit;
2318
- const completed = limit === -1 || offset >= total;
2319
- if (completed) {
2320
- log(`Audit completed`);
2321
- }
2322
-
2323
- const tEnd = new Date();
2324
- const secs = secondBetweenTwoDate(timeStart, tEnd);
2325
- log(`Execution time: ${secs} seconds`);
2326
-
2327
- if (serverUtils) {
2328
- serverUtils.log(`Audit completed`);
2329
- serverUtils.updateProgress(100);
2330
- }
2331
-
2332
- return {
2333
- offset: nextOffset,
2334
- limit: limit,
2335
- completed,
2336
- s3FilePath,
2337
- total,
2338
- processedEntries: 0,
2339
- };
2340
- }
2341
-
2342
- const pageCodes = productEntries.map((entry: Entry) =>
2343
- getProductPageIdByCode(entry.fields.code[defaultEnvironmentLocaleCode])
2344
- );
2345
-
2346
- log(`Get ${pageCodes.length} product page entry from Contentful`);
2347
- const productPageEntries = await getAllEntriesByCodes(
2348
- pageCodes,
2349
- "page",
2350
- "sys,fields",
2351
- "sys.id"
2352
- );
2353
- log(`Founded ${productPageEntries.length} topicProduct pages`);
2354
-
2355
- let count: number = offset;
2356
- let current: number = 0;
2357
- for (const audit of allAudit) {
2358
- log(`${++count} of ${total}`);
2359
- log(`I process the item ${audit.product} with status ${audit.what}`);
2360
-
2361
- if (productAuditWhat.includes(audit.what)) {
2362
- const result = await productAudit(
2363
- audit,
2364
- productEntries,
2365
- catalog,
2366
- defaultEnvironmentLocaleCode,
2367
- current,
2368
- allAudit,
2369
- productPageEntries
2370
- );
2371
- current = result.current;
2372
- if (result.continue) {
2373
- continue;
2374
- }
2375
- } else if (audit.what === "REMOVE_FAMILY_RELATIONS") {
2376
- const result = await familyAudit(
2377
- audit,
2378
- familyEntries,
2379
- catalog,
2380
- defaultEnvironmentLocaleCode,
2381
- current,
2382
- allAudit
2383
- );
2384
- current = result.current;
2385
- if (result.continue) {
2386
- continue;
2387
- }
2388
- } else if (audit.what === "REMOVE_SUBFAMILY_RELATIONS") {
2389
- const result = await subFamilyAudit(
2390
- audit,
2391
- subFamilyEntries,
2392
- catalog,
2393
- defaultEnvironmentLocaleCode,
2394
- current,
2395
- allAudit
2396
- );
2397
- current = result.current;
2398
- if (result.continue) {
2399
- continue;
2400
- }
2401
- }
2402
-
2403
- if (serverUtils) {
2404
- serverUtils.log(audit.product);
2405
- const progress = Math.floor((++current / allAudit.length) * 100);
2406
- serverUtils.updateProgress(progress);
2407
- }
2408
- }
2409
-
2410
- const nextOffset = offset + limit;
2411
- const tEnd = new Date();
2412
- const secs = secondBetweenTwoDate(timeStart, tEnd);
2413
- log(`Execution time: ${secs} seconds`);
2414
-
2415
- return {
2416
- offset: nextOffset,
2417
- limit,
2418
- completed: limit === -1 || count >= total,
2419
- s3FilePath,
2420
- total,
2421
- processedEntries:
2422
- productEntries.length + familyEntries.length + subFamilyEntries.length,
2423
- };
2424
- } else {
2425
- log(`Execution completed`);
2426
- if (serverUtils) {
2427
- serverUtils.log(`Execution completed`);
2428
- serverUtils.updateProgress(100);
2429
- }
2430
- }
2431
- const tEnd = new Date();
2432
- const secs = secondBetweenTwoDate(timeStart, tEnd);
2433
- log(`Request time: ${secs} seconds`);
2434
-
2435
- return {
2436
- offset: offset,
2437
- limit: limit,
2438
- completed: true,
2439
- s3FilePath,
2440
- processedEntries: 0,
2441
- };
2442
- };
2443
-
2444
- export const importProductByCode = async (
2445
- code: string,
2446
- catalog: AvailableCatalogs
2447
- ) => {
2448
- const timeStart = new Date();
2449
- log(`importProductByCode - code: ${code} catalog: ${catalog}`, "INFO");
2450
- const productDetails = await getProductDetails(code);
2451
-
2452
- if (productDetails) {
2453
- await importProduct(productDetails, catalog);
2454
- }
2455
-
2456
- const tEnd = new Date();
2457
- const secs = secondBetweenTwoDate(timeStart, tEnd);
2458
- log(`Request time: ${secs} seconds`);
2459
- };
2460
-
2461
- /**
2462
- * Generate Tech Spec PDF by topicProducId
2463
- *
2464
- * @param topicProductId
2465
- * @returns
2466
- */
2467
- export const generateTechSpecPdf = async (
2468
- topicProductId: string,
2469
- country: string = "global",
2470
- locale: string = "en"
2471
- ) => {
2472
- log(`generateTechSpecPdf - topicProductId: ${topicProductId}`);
2473
- const defaultEnvironmentLocaleCode = await getEnvironmentDefaultLocaleCode();
2474
- let topicProduct = await getEntryByID(
2475
- topicProductId,
2476
- "topicProduct",
2477
- "",
2478
- locale
2479
- );
2480
- if (!topicProduct) {
2481
- throw new Error(`topicProduct with id ${topicProductId} not found`);
2482
- } else if (topicProduct.isArchived()) {
2483
- throw new Error(`topicProduct with id ${topicProductId} is archived`);
2484
- }
2485
- if (serverUtils) {
2486
- serverUtils.updateProgress(10);
2487
- }
2488
-
2489
- const topicProductPageId = getProductPageIdByCode(topicProduct.sys.id);
2490
- const topicProductPage = await getEntryByID(
2491
- topicProductPageId,
2492
- "page",
2493
- "",
2494
- locale
2495
- );
2496
- if (!topicProductPage) {
2497
- throw new Error(`topicProductPage with id ${topicProductPageId} not found`);
2498
- } else if (topicProductPage.isArchived()) {
2499
- throw new Error(
2500
- `topicProductPage with id ${topicProductPageId} is archived`
2501
- );
2502
- }
2503
-
2504
- if (serverUtils) {
2505
- serverUtils.updateProgress(20);
2506
- }
2507
-
2508
- const topicCatalogIds = topicProduct?.fields?.catalogs?.[
2509
- defaultEnvironmentLocaleCode
2510
- ]?.map((catalog: any) => catalog.sys.id);
2511
- const pageSlug =
2512
- topicProductPage?.fields?.slug?.[locale] ??
2513
- topicProductPage?.fields?.slug?.[defaultEnvironmentLocaleCode];
2514
- const version = topicProduct?.sys?.version;
2515
- const fileName =
2516
- (pageSlug.length >= 170
2517
- ? `tech-spec-${topicProductId}`
2518
- : `tech-spec-${pageSlug}`) + `_${country}-${locale}`; // 57 caratteri è il resto dell'url di S3
2519
- let baseUrl = process.env.FPI_TECH_SPEC_BASE_URL ?? "";
2520
- if (!baseUrl) {
2521
- log(`FPI_TECH_SPEC_BASE_URL process env not found`, "ERROR");
2522
- }
2523
- baseUrl = baseUrl.replace(/\/?(\?|#|$)/, "/$1");
2524
- let footerBaseUrl =
2525
- process.env.FPI_TECH_SPEC_FOOTER_BASE_URL ??
2526
- process.env.FPI_TECH_SPEC_BASE_URL ??
2527
- "";
2528
- if (!footerBaseUrl) {
2529
- log(`FPI_TECH_SPEC_FOOTER_BASE_URL process env not found`, "ERROR");
2530
- }
2531
- footerBaseUrl = footerBaseUrl.replace(/\/?(\?|#|$)/, "/$1");
2532
-
2533
- const layoutUrl = `${baseUrl}${locale}/${country}/tech-spec/${pageSlug}/v-${version}/`;
2534
- const pdpSiteUrl =
2535
- `${footerBaseUrl}${locale}/${country}/product/${pageSlug}`.replace(
2536
- /\/?(\?|#|$)/,
2537
- "/$1"
2538
- );
2539
- log(`pdpSiteUrl: ${pdpSiteUrl}`);
2540
- const contents = {
2541
- // header: {
2542
- // right: "Technical Specifications",
2543
- // },
2544
- footer: {
2545
- topLeft: `<a style="text-decoration: none; color:#000" href="${pdpSiteUrl}">${pdpSiteUrl}</a>`,
2546
- topRight: topicProductId,
2547
- bottomLeft: ``,
2548
- bottomRight: ``,
2549
- mail: topicCatalogIds.includes("OUTDOOR")
2550
- ? "flos.outdoor@flos.com"
2551
- : "info@flos.com",
2552
- },
2553
- };
2554
-
2555
- if (serverUtils) {
2556
- serverUtils.updateProgress(35);
2557
- }
2558
-
2559
- const s3Url = await generatePDFByUrl(layoutUrl, fileName, contents);
2560
- if (s3Url) {
2561
- if (serverUtils) {
2562
- serverUtils.log("PDF saved to S3!");
2563
- serverUtils.log(`Update techSpec field...`);
2564
- serverUtils.updateProgress(75);
2565
- }
2566
-
2567
- log(`Update techSpec field...`);
2568
- topicProduct.fields = await addFieldValue(
2569
- topicProduct,
2570
- "techSpec",
2571
- s3Url,
2572
- false,
2573
- locale
2574
- );
2575
-
2576
- topicProduct = await topicProduct.update();
2577
- if (topicProduct.isPublished()) {
2578
- try {
2579
- topicProduct = await topicProduct.publish();
2580
- } catch (err: any) {
2581
- log(`Cannot publish entry.`);
2582
- log(err);
2583
- }
2584
- }
2585
-
2586
- if (serverUtils) {
2587
- serverUtils.log("Updated!");
2588
- serverUtils.updateProgress(100);
2589
- }
2590
-
2591
- log(`${topicProductId} techSpec field updated!`);
2592
- return s3Url;
2593
- } else {
2594
- throw new Error(
2595
- `TechSpec PDF generation failed for product: ${topicProductId}!`
2596
- );
2597
- }
2598
- };
2599
-
2600
- const getLightModuleAutoDescriptionByProductFields = async (
2601
- productFileds: any
2602
- ) => {
2603
- const autoDescription: any = {};
2604
- const dictionaryJson = await getDictionaryJson();
2605
- for (const locale of cfLocales) {
2606
- if (!autoDescription?.[locale]) {
2607
- autoDescription[locale] = "";
2608
- }
2609
- let addSeparator = false;
2610
- if (productFileds?.electrical?.lampCategories) {
2611
- const lampCategoriesLocalizedValues = [];
2612
- for (const lampCategory of productFileds.electrical.lampCategories) {
2613
- const lampCategoryLocalizedValue = await getDictionaryLocaleValue(
2614
- locale,
2615
- "lampCategories",
2616
- lampCategory.code,
2617
- "electrical",
2618
- dictionaryJson
2619
- );
2620
- if (lampCategoryLocalizedValue) {
2621
- lampCategoriesLocalizedValues.push(lampCategoryLocalizedValue);
2622
- }
2623
- }
2624
-
2625
- if (lampCategoriesLocalizedValues.length) {
2626
- if (addSeparator) {
2627
- autoDescription[locale] += " - ";
2628
- } else {
2629
- addSeparator = true;
2630
- }
2631
- autoDescription[locale] += lampCategoriesLocalizedValues.join(", ");
2632
- if (
2633
- productFileds.electrical.lampCategories.find(
2634
- (item: any) => item.code === "LAMPCAT4"
2635
- ) &&
2636
- productFileds?.photometric?.ledTypes?.length
2637
- ) {
2638
- const ledTypeLocalizedValues = [];
2639
- for (const ledType of productFileds?.photometric?.ledTypes) {
2640
- const ledTypeLocalizedValue = await getDictionaryLocaleValue(
2641
- locale,
2642
- "ledTypes",
2643
- ledType.code,
2644
- "photometric",
2645
- dictionaryJson
2646
- );
2647
- if (ledTypeLocalizedValue) {
2648
- ledTypeLocalizedValues.push(ledTypeLocalizedValue);
2649
- }
2650
- }
2651
-
2652
- if (ledTypeLocalizedValues.length) {
2653
- if (addSeparator) {
2654
- autoDescription[locale] += " - ";
2655
- } else {
2656
- addSeparator = true;
2657
- }
2658
- autoDescription[locale] += ledTypeLocalizedValues.join(", ");
2659
- }
2660
- }
2661
- }
2662
- }
2663
-
2664
- if (productFileds?.electrical?.wPower) {
2665
- if (addSeparator) {
2666
- autoDescription[locale] += " - ";
2667
- } else {
2668
- addSeparator = true;
2669
- }
2670
- if (productFileds?.optical?.numberOfHeads >= 2) {
2671
- autoDescription[locale] += `${productFileds.optical.numberOfHeads} x `;
2672
- }
2673
- autoDescription[locale] += `${productFileds.electrical.wPower}W`;
2674
- }
2675
- if (productFileds?.photometric?.realNetFlow) {
2676
- if (addSeparator) {
2677
- autoDescription[locale] += " - ";
2678
- } else {
2679
- addSeparator = true;
2680
- }
2681
- if (productFileds?.optical?.numberOfHeads >= 2) {
2682
- autoDescription[locale] += `${productFileds.optical.numberOfHeads} x `;
2683
- }
2684
- autoDescription[locale] += `${productFileds.photometric.realNetFlow}lm`;
2685
- }
2686
-
2687
- if (productFileds?.photometric?.temperatureColor?.code) {
2688
- const temperatireColorLocalizedValue = await getDictionaryLocaleValue(
2689
- locale,
2690
- "temperatureColor",
2691
- productFileds.photometric.temperatureColor.code,
2692
- "photometric",
2693
- dictionaryJson
2694
- );
2695
- if (temperatireColorLocalizedValue) {
2696
- if (addSeparator) {
2697
- autoDescription[locale] += " - ";
2698
- } else {
2699
- addSeparator = true;
2700
- }
2701
- autoDescription[locale] += temperatireColorLocalizedValue + "K";
2702
- }
2703
- }
2704
-
2705
- if (productFileds?.photometric?.cri?.code) {
2706
- const CriLocalizedValue = await getDictionaryLocaleValue(
2707
- locale,
2708
- "cri",
2709
- productFileds.photometric.cri.code,
2710
- "photometric",
2711
- dictionaryJson
2712
- );
2713
- if (CriLocalizedValue) {
2714
- if (addSeparator) {
2715
- autoDescription[locale] += " - ";
2716
- } else {
2717
- addSeparator = true;
2718
- }
2719
- autoDescription[locale] += "CRI> " + CriLocalizedValue;
2720
- }
2721
- }
2722
-
2723
- if (productFileds?.photometric?.beam0_180) {
2724
- if (addSeparator) {
2725
- autoDescription[locale] += " - ";
2726
- } else {
2727
- addSeparator = true;
2728
- }
2729
- autoDescription[locale] += "Beam° " + productFileds.photometric.beam0_180;
2730
- }
2731
- }
2732
-
2733
- return autoDescription;
2734
- };
2735
-
2736
- const getOtherAutoDescriptionByProductFields = async (productFileds: any) => {
2737
- const autoDescription: any = {};
2738
- const dictionaryJson = await getDictionaryJson();
2739
- for (const locale of cfLocales) {
2740
- if (!autoDescription?.[locale]) {
2741
- autoDescription[locale] = "";
2742
- }
2743
- let addSeparator = false;
2744
- // Profile and others
2745
- if (productFileds?.physical?.length_us && locale === "en-US") {
2746
- autoDescription[locale] += "Length: " + productFileds.physical.length_us;
2747
- addSeparator = true;
2748
- } else if (productFileds?.physical?.length && locale !== "en-US") {
2749
- autoDescription[locale] += "Length: " + productFileds.physical.length;
2750
- addSeparator = true;
2751
- }
2752
-
2753
- if (productFileds?.mountings) {
2754
- const mountingsLocalizedValues = [];
2755
- for (const mounting of productFileds.mountings) {
2756
- const mountingLocalizedValue = await getDictionaryLocaleValue(
2757
- locale,
2758
- "mountings",
2759
- mounting.code,
2760
- "",
2761
- dictionaryJson
2762
- );
2763
- if (mountingLocalizedValue) {
2764
- mountingsLocalizedValues.push(mountingLocalizedValue);
2765
- }
2766
- }
2767
-
2768
- if (addSeparator) {
2769
- autoDescription[locale] += " - ";
2770
- } else {
2771
- addSeparator = true;
2772
- }
2773
- autoDescription[locale] += mountingsLocalizedValues.join(", ");
2774
- }
2775
- }
2776
-
2777
- return autoDescription;
2778
- };
2779
-
2780
- /**
2781
- * Get topicProduct autoDescription
2782
- *
2783
- * @param topicProduct
2784
- * @returns
2785
- */
2786
- const getTopicProductAutodescription = async (
2787
- topicProductFields: KeyValueMap
2788
- ) => {
2789
- const defaultEnvironmentLocaleCode = await getEnvironmentDefaultLocaleCode();
2790
- const productLineCode =
2791
- topicProductFields?.productLine?.[defaultEnvironmentLocaleCode]?.sys?.id;
2792
- const productFileds =
2793
- topicProductFields?.productFields?.[defaultEnvironmentLocaleCode];
2794
-
2795
- let autoDescription: any = {};
2796
- switch (productLineCode) {
2797
- case "PLINE6": // Soft Plate
2798
- case "PLINE5": // Light Bulb
2799
- case "PLINE3": // Driver
2800
- case "PLINE2": // Accessory
2801
- // post_content
2802
- autoDescription = topicProductFields?.description;
2803
- break;
2804
- case "PLINE1": // Light Module
2805
- autoDescription = await getLightModuleAutoDescriptionByProductFields(
2806
- productFileds
2807
- );
2808
-
2809
- break;
2810
- default:
2811
- autoDescription = await getOtherAutoDescriptionByProductFields(
2812
- productFileds
2813
- );
2814
-
2815
- break;
2816
- }
2817
-
2818
- return autoDescription;
2819
- };
2820
-
2821
- const setProductAutodescription = async (topicProduct: Entry) => {
2822
- log(`Set audtodescription of the topic ${topicProduct.sys.id}`);
2823
- const autoDescription = await getTopicProductAutodescription(
2824
- topicProduct.fields
2825
- );
2826
- topicProduct.fields.autoDescription = autoDescription;
2827
- if (!topicProduct.isArchived()) {
2828
- topicProduct = await topicProduct.update();
2829
- if (topicProduct.isPublished()) {
2830
- topicProduct = await topicProduct.publish();
2831
- }
2832
- } else {
2833
- log(
2834
- `Product ${topicProduct.sys.id} is archived, it is not possible to update the autodescription`,
2835
- "WARN"
2836
- );
2837
- }
2838
-
2839
- return autoDescription;
2840
- };
2841
-
2842
- export const setProductsAutodescription = async (
2843
- catalog: AvailableCatalogs,
2844
- offset: number = 0,
2845
- limit: number = 100
2846
- ) => {
2847
- log(
2848
- `setProductAutodescription - catalog: ${catalog}, offset: ${offset}, limit: ${limit}`,
2849
- "INFO"
2850
- );
2851
- const env = await getEnvironment();
2852
- const defEnvLocaleCode = await getEnvironmentDefaultLocaleCode();
2853
-
2854
- const { items, total } = await env.getEntries({
2855
- content_type: "topicProduct",
2856
- "fields.catalogs.sys.id": catalog,
2857
- limit,
2858
- skip: offset,
2859
- locale: defEnvLocaleCode,
2860
- include: 0,
2861
- select: "sys,fields",
2862
- "sys.archivedAt[exists]": false,
2863
- });
2864
-
2865
- let count = 0;
2866
- for (const item of items) {
2867
- setProductAutodescription(item);
2868
-
2869
- if (++count % 5 === 0) {
2870
- log(
2871
- `current: ${count} of ${limit} - global: ${offset + count} of ${total}`
2872
- );
2873
- await sleep(3000, true);
2874
- }
2875
- }
2876
-
2877
- return {
2878
- catalog,
2879
- offset: Number(offset) + Number(limit),
2880
- limit: Number(limit),
2881
- completed: Number(offset) + Number(limit) >= total,
2882
- total,
2883
- };
2884
- };
2885
-
2886
- export const setProductAutodescriptionByTopicId = async (
2887
- topicProductId: string
2888
- ) => {
2889
- const topicProduct = await getEntryByID(topicProductId, "topicProduct");
2890
-
2891
- return await setProductAutodescription(topicProduct);
2892
- };
2893
-
2894
- export const getProductAutodescription = async (topicProductId: string) => {
2895
- const topicProduct = await getEntryByID(topicProductId, "topicProduct");
2896
-
2897
- return await getTopicProductAutodescription(topicProduct.fields);
2898
- };
2899
-
2900
- export const removeProductFromColorVariantsByProductLine = async (
2901
- productLineCode: string
2902
- ) => {
2903
- log(`Serch topicProduct with productLine ${productLineCode}`);
2904
- const topicProducts = await getAllEntries(
2905
- "topicProduct",
2906
- "sys",
2907
- "fields.productLine.sys.id",
2908
- productLineCode
2909
- );
2910
- const topicProductCodes = topicProducts.map(
2911
- (topicProduct) => topicProduct.sys.id
2912
- );
2913
-
2914
- log(`Founded ${topicProductCodes.length} topicProducts`);
2915
-
2916
- let count = 0;
2917
- for (const topicProductCode of topicProductCodes) {
2918
- log(`${++count} of ${topicProductCodes.length}`);
2919
- log(
2920
- `Serch topicProductColourVariants of the ${topicProductCode} topicProduct`
2921
- );
2922
- const topicProductColourVariants = await getAllEntries(
2923
- "topicProductColourVariants",
2924
- "sys,fields",
2925
- "fields.products.sys.id[in]",
2926
- topicProductCode
2927
- );
2928
-
2929
- if (topicProductColourVariants.length) {
2930
- const defaultEnvironmentLocaleCode =
2931
- await getEnvironmentDefaultLocaleCode();
2932
- log(
2933
- `${topicProductColourVariants.length} topicProductColourVariants founded`
2934
- );
2935
- for (let topicProductColourVariant of topicProductColourVariants) {
2936
- log(
2937
- `Remove the ${topicProductCode} topicProduct from the ${topicProductColourVariant.sys.id} topicProductColourVariants`
2938
- );
2939
-
2940
- topicProductColourVariant.fields.products[
2941
- defaultEnvironmentLocaleCode
2942
- ] = topicProductColourVariant.fields.products[
2943
- defaultEnvironmentLocaleCode
2944
- ].filter((item: CfSys) => item.sys.id !== topicProductCode);
2945
-
2946
- if (
2947
- topicProductColourVariant.fields.products[
2948
- defaultEnvironmentLocaleCode
2949
- ].length
2950
- ) {
2951
- log(
2952
- `Update the ${topicProductColourVariant.sys.id} topicProductColourVariants`
2953
- );
2954
- topicProductColourVariant = await topicProductColourVariant.update();
2955
- if (topicProductColourVariant.isPublished()) {
2956
- topicProductColourVariant =
2957
- await topicProductColourVariant.publish();
2958
- }
2959
- } else {
2960
- log(
2961
- `Remove the ${topicProductColourVariant.sys.id} topicProductColourVariants because don't have more topicProducts`
2962
- );
2963
- if (topicProductColourVariant.isPublished()) {
2964
- topicProductColourVariant =
2965
- await topicProductColourVariant.unpublish();
2966
- }
2967
- await topicProductColourVariant.delete();
2968
- }
2969
- }
2970
- } else {
2971
- log(
2972
- `No topicProductColourVariants found for the ${topicProductCode} topicProduct`
2973
- );
2974
- }
2975
- }
2976
- };
2977
-
2978
- /**
2979
- * Remove a specific model from all product model relations
2980
- * NOTE: require the reindex of all product updated
2981
- *
2982
- * @param modelCode
2983
- */
2984
- export const removeAllProductModelProductRelations = async (
2985
- modelCode: string
2986
- ) => {
2987
- log(`removeAllProductModelProductRelations - modelCode: ${modelCode}`);
2988
- const env = await getEnvironment();
2989
- const defEnvLocaleCode = await getEnvironmentDefaultLocaleCode();
2990
- const { items } = await env.getEntries({
2991
- content_type: "topicProduct",
2992
- locale: defEnvLocaleCode,
2993
- include: 2,
2994
- links_to_entry: modelCode,
2995
- limit: 1000,
2996
- });
2997
-
2998
- log(`Founded ${items.length} products`);
2999
-
3000
- const allProductModelFields = [
3001
- "modelsArchitectural",
3002
- "modelsOutdoor",
3003
- "modelsDecorative",
3004
- ];
3005
- for (let item of items) {
3006
- for (const modelFieldKey of allProductModelFields) {
3007
- if (
3008
- item.fields?.[modelFieldKey]?.[defEnvLocaleCode].find(
3009
- (model: CfSys) => model.sys.id === modelCode
3010
- )
3011
- ) {
3012
- item.fields[modelFieldKey][defEnvLocaleCode] = item.fields[
3013
- modelFieldKey
3014
- ][defEnvLocaleCode].filter(
3015
- (model: CfSys) => model.sys.id !== modelCode
3016
- );
3017
- }
3018
- }
3019
-
3020
- const productCode = item.fields.code[defEnvLocaleCode];
3021
- if (item.isArchived()) {
3022
- log(`Product with code ${productCode} is archived`, "WARN");
3023
- } else {
3024
- item = await item.update();
3025
- log(`Updated product ${productCode}`);
3026
- // log(`"${productCode}",`);
3027
- }
3028
- if (item.isPublished()) {
3029
- item = await item.publish();
3030
- }
3031
- }
3032
- };
3033
-
3034
- /**
3035
- *
3036
- * Reimport audit products
3037
- *
3038
- * @param {string} lastModified The last modified data. Format: 20200426T07:50:00 - yearmonthdayThour:minute:second
3039
- * @param {string} catalog
3040
- */
3041
- export const reimportAuditProducts = async (
3042
- lastModified: string,
3043
- catalog: AvailableCatalogs,
3044
- offset: number = 0,
3045
- limit: number = 150,
3046
- s3FilePath: string = ""
3047
- ) => {
3048
- // if not exists save data to s3
3049
- if (!s3FilePath) {
3050
- const allAudit = await getAudit(lastModified);
3051
- const allFilteredAudit = allAudit.filter((audit) =>
3052
- ["PRODUCT_WEBOFF", "PRODUCT_UNPUBLISH"].includes(audit.what)
3053
- );
3054
- if (!allFilteredAudit) {
3055
- log(`No audits were found to process for the date ${lastModified}`);
3056
- return {
3057
- offset,
3058
- limit,
3059
- completed: true,
3060
- s3FilePath: "",
3061
- total: 0,
3062
- processedEntries: 0,
3063
- };
3064
- }
3065
-
3066
- const filename = `${lastModified}-all-audit-web-off.json`;
3067
- const path = `audit/reimport`;
3068
- await saveJsonToS3(allFilteredAudit, filename, path);
3069
- const s3Path = `${path}/${filename}`;
3070
-
3071
- return {
3072
- offset: Number(offset),
3073
- limit: Number(limit),
3074
- completed: false,
3075
- s3FilePath: s3Path,
3076
- total: allAudit.length,
3077
- processedEntries: 0,
3078
- };
3079
- }
3080
-
3081
- // get data from s3
3082
- log(`Get audit details from ${s3FilePath}`);
3083
- let allAudit: Audit[] = await getFileFromS3(s3FilePath);
3084
- const total: number = allAudit.length;
3085
- allAudit = allAudit.slice(offset, offset + limit);
3086
- log(`Founded ${allAudit.length} items`);
3087
-
3088
- if (allAudit) {
3089
- const defaultEnvironmentLocaleCode =
3090
- await getEnvironmentDefaultLocaleCode();
3091
-
3092
- const productCodes = allAudit.map((audit) => audit.product);
3093
- const otherFilters = [];
3094
- if (catalog) {
3095
- otherFilters.push({ key: "fields.catalogs.sys.id[in]", value: catalog });
3096
- }
3097
- log(`Get ${productCodes.length} product entry from Contentful`);
3098
- const entries = await getAllEntriesByCodes(
3099
- productCodes,
3100
- "topicProduct",
3101
- "sys,fields",
3102
- "fields.code",
3103
- otherFilters
3104
- );
3105
- log(`Founded ${entries.length} topicProduct`);
3106
-
3107
- if (!entries.length) {
3108
- log(
3109
- `No products found between offset: ${offset} and limit: ${limit}. Total: ${total}`
3110
- );
3111
- const nextOffset = offset + limit;
3112
- const completed = limit === -1 || offset >= total;
3113
- if (completed) {
3114
- log(`Audit completed`);
3115
- }
3116
-
3117
- return {
3118
- offset: nextOffset,
3119
- limit: limit,
3120
- completed,
3121
- s3FilePath,
3122
- total,
3123
- processedEntries: 0,
3124
- };
3125
- }
3126
-
3127
- const pageCodes = entries.map((entry: Entry) =>
3128
- getProductPageIdByCode(entry.fields.code[defaultEnvironmentLocaleCode])
3129
- );
3130
-
3131
- log(`Get ${pageCodes.length} product page entry from Contentful`);
3132
- const entriesPage = await getAllEntriesByCodes(
3133
- pageCodes,
3134
- "page",
3135
- "sys,fields",
3136
- "sys.id"
3137
- );
3138
- log(`Founded ${entriesPage.length} topicProduct pages`);
3139
- let count: number = offset;
3140
- for (const audit of allAudit) {
3141
- log(`${++count} of ${total}`);
3142
- log(`I process the product ${audit.product} with status ${audit.what}`);
3143
-
3144
- log(`Search product entry with id ${audit.product}...`);
3145
- const productEntry = entries.find(
3146
- (currentEntry) =>
3147
- currentEntry?.fields?.code?.[defaultEnvironmentLocaleCode] ===
3148
- audit.product
3149
- );
3150
-
3151
- if (!productEntry) {
3152
- let logMessage = "";
3153
- if (catalog) {
3154
- logMessage = `The ${audit.product} product was not found in the CMS with catalog ${catalog}`;
3155
- } else {
3156
- logMessage = `The ${audit.product} product was not found in the CMS`;
3157
- }
3158
- log(logMessage, "WARN");
3159
-
3160
- continue;
3161
- }
3162
-
3163
- log(`Founded product with id ${productEntry.sys.id}`);
3164
-
3165
- log(`Get product catalogs...`);
3166
- const productCatalogs: AvailableCatalogs[] =
3167
- productEntry?.fields?.catalogs?.[defaultEnvironmentLocaleCode].map(
3168
- (entryCatalog: FieldItem) => {
3169
- return entryCatalog.sys.id;
3170
- }
3171
- );
3172
-
3173
- if (catalog && !productCatalogs.includes(catalog)) {
3174
- log(
3175
- `Product ${audit.product} does not belong to the ${catalog} catalog`
3176
- );
3177
- } else {
3178
- log(`Import product...`);
3179
- await importProductByCode(audit.product, catalog);
3180
- await reindexProduct(audit.product, true);
3181
- }
3182
- }
3183
-
3184
- const nextOffset = offset + limit;
3185
-
3186
- return {
3187
- offset: nextOffset,
3188
- limit,
3189
- completed: limit === -1 || count >= total,
3190
- s3FilePath,
3191
- total,
3192
- processedEntries: entries.length,
3193
- };
3194
- } else {
3195
- log(`Execution completed`);
3196
- }
3197
-
3198
- return {
3199
- offset: offset,
3200
- limit: limit,
3201
- completed: true,
3202
- s3FilePath,
3203
- processedEntries: 0,
3204
- };
3205
- };
3206
-
3207
- export const populateDestinations = async (offset: number, limit: number) => {
3208
- const env = await getEnvironment();
3209
- const defEnvLocaleCode = await getEnvironmentDefaultLocaleCode();
3210
-
3211
- const opts = {
3212
- content_type: "topicProduct",
3213
- skip: offset,
3214
- limit,
3215
- locale: defEnvLocaleCode,
3216
- // select: 'sys.id,fields',
3217
- "sys.archivedAt[exists]": false,
3218
- // "fields.destinations[exists]": false,
3219
- };
3220
-
3221
- const { items, total } = await env.getEntries(opts);
3222
-
3223
- let count: number = offset;
3224
- for (let productEntry of items) {
3225
- log(`${++count} of ${total}`);
3226
- log(`Product: ${productEntry.sys.id}`);
3227
- const destinations =
3228
- productEntry.fields.productFields[defEnvLocaleCode]?.destinations?.map(
3229
- (destination: any) => destination.code
3230
- ) || [];
3231
-
3232
- if (destinations.length) {
3233
- log(`Set destinations: ${destinations.join(", ")}`);
3234
- productEntry.fields = await addFieldValue(
3235
- productEntry,
3236
- "destinations",
3237
- destinations
3238
- );
3239
- productEntry = await productEntry.update();
3240
- } else {
3241
- log(`No destinations found.`, "WARN");
3242
- }
3243
-
3244
- if (productEntry.isPublished()) {
3245
- try {
3246
- productEntry = await productEntry.publish();
3247
- } catch (err: any) {
3248
- log(`Cannot publish entry.`);
3249
- log(err);
3250
- }
3251
- }
3252
- }
3253
-
3254
- return { completed: !total || total === count + offset, offset, limit };
3255
- };
3256
-
3257
- export const purgeProductThumbCacheByProductCodes = async (
3258
- productCodes: string[]
3259
- ) => {
3260
- const defEnvLocaleCode = await getEnvironmentDefaultLocaleCode();
3261
-
3262
- const productEntries = await getAllEntriesByCodes(
3263
- productCodes,
3264
- "topicProduct",
3265
- "sys,fields.thumbnailImgix"
3266
- );
3267
-
3268
- let count: number = 0;
3269
- const total: number = productEntries.length;
3270
- for (const productEntry of productEntries) {
3271
- log(`${++count} of ${total}`);
3272
- const thumbEntryId =
3273
- productEntry.fields?.thumbnailImgix?.[defEnvLocaleCode]?.sys?.id;
3274
-
3275
- if (thumbEntryId) {
3276
- let wrapperImgix = await getEntryByID(
3277
- thumbEntryId,
3278
- "wrapperImgix",
3279
- "sys,fields"
3280
- );
3281
- if (wrapperImgix) {
3282
- const imgixUrl =
3283
- wrapperImgix.fields?.imgixData?.[defEnvLocaleCode]?.url;
3284
- if (imgixUrl) {
3285
- log(`Cleaning cache for ${imgixUrl}`);
3286
- await purgeImageCacheByUrl(imgixUrl);
3287
- } else {
3288
- log(`No imgixUrl found in ${thumbEntryId} id`, "WARN");
3289
- }
3290
- } else {
3291
- log(`No wrapperImgix found with ${thumbEntryId} id`, "WARN");
3292
- }
3293
- } else {
3294
- log(`No thumbEntryId found in ${productEntry.sys.id}`, "WARN");
3295
- }
3296
- }
3297
- };