@haus-tech/product-import-export-plugin 2.2.0-dev.1 → 2.2.0-dev.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/providers/import-providers/asset-importer.js +13 -2
- package/dist/providers/import-providers/product-importer.js +21 -4
- package/dist/services/extended-fast-importer.service.d.ts +3 -1
- package/dist/services/extended-fast-importer.service.js +20 -0
- package/dist/types.d.ts +1 -1
- package/dist/ui/components/product-import.component.d.ts +1 -1
- package/dist/ui/components/product-import.component.html +7 -4
- package/dist/ui/components/product-import.component.js +1 -0
- package/dist/ui/components/product-import.component.ts +2 -1
- package/dist/ui/translations/en.json +1 -0
- package/dist/ui/translations/sv.json +1 -0
- package/package.json +1 -1
|
@@ -45,12 +45,16 @@ let ExtendedAssetImporter = class ExtendedAssetImporter {
|
|
|
45
45
|
for (const assetPath of uniqueAssetPaths.values()) {
|
|
46
46
|
const cachedAsset = this.assetMap.get(assetPath.url);
|
|
47
47
|
if (cachedAsset) {
|
|
48
|
-
if (
|
|
48
|
+
if (cachedAsset.name !== assetPath.name && assetPath.name) {
|
|
49
49
|
this.connection.getRepository(ctx, core_1.Asset).update(cachedAsset.id, {
|
|
50
50
|
name: assetPath.name,
|
|
51
51
|
});
|
|
52
|
+
this.assetMap.set(assetPath.url, { ...cachedAsset, name: assetPath.name });
|
|
53
|
+
assets.push({ ...cachedAsset, name: assetPath.name });
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
assets.push(cachedAsset);
|
|
52
57
|
}
|
|
53
|
-
assets.push(cachedAsset);
|
|
54
58
|
}
|
|
55
59
|
else {
|
|
56
60
|
try {
|
|
@@ -65,6 +69,12 @@ let ExtendedAssetImporter = class ExtendedAssetImporter {
|
|
|
65
69
|
},
|
|
66
70
|
});
|
|
67
71
|
if (assetFromHash) {
|
|
72
|
+
// Check if the asset name has changed
|
|
73
|
+
if (assetPath.name && assetFromHash.name !== assetPath.name) {
|
|
74
|
+
await this.connection.getRepository(ctx, core_1.Asset).update(assetFromHash.id, {
|
|
75
|
+
name: assetPath.name,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
68
78
|
this.assetMap.set(assetPath.url, assetFromHash);
|
|
69
79
|
assets.push(assetFromHash);
|
|
70
80
|
continue;
|
|
@@ -89,6 +99,7 @@ let ExtendedAssetImporter = class ExtendedAssetImporter {
|
|
|
89
99
|
shouldDeleteCreatedAsset = true;
|
|
90
100
|
assetToUpdate = { ...assetFromHash, name: assetPath.name || assetFromHash.name };
|
|
91
101
|
}
|
|
102
|
+
console.log('assetFromHash', assetFromHash);
|
|
92
103
|
if (assetPath.id) {
|
|
93
104
|
shouldDeleteCreatedAsset = true;
|
|
94
105
|
assetToUpdate = {
|
|
@@ -294,6 +294,7 @@ let ProductImporter = class ProductImporter {
|
|
|
294
294
|
'variants',
|
|
295
295
|
'variants.facetValues',
|
|
296
296
|
'assets',
|
|
297
|
+
'featuredAsset',
|
|
297
298
|
],
|
|
298
299
|
})
|
|
299
300
|
: undefined;
|
|
@@ -322,10 +323,17 @@ let ProductImporter = class ProductImporter {
|
|
|
322
323
|
previousNormalizedName: (0, normalize_string_1.normalizeString)(existingProductName),
|
|
323
324
|
}
|
|
324
325
|
: undefined;
|
|
326
|
+
if (existingProduct && updatingStrategy === 'replace') {
|
|
327
|
+
await this.fastImporter.removeAllAssetsFromProduct(existingProduct);
|
|
328
|
+
}
|
|
325
329
|
const productData = {
|
|
326
|
-
featuredAssetId:
|
|
330
|
+
featuredAssetId: existingProduct?.featuredAsset
|
|
331
|
+
? undefined
|
|
332
|
+
: productAssets.length
|
|
333
|
+
? productAssets[0].id
|
|
334
|
+
: undefined,
|
|
327
335
|
assetIds: productAssets.map((a) => a.id),
|
|
328
|
-
|
|
336
|
+
facetValueIds: updatingStrategy === 'replace' ? [] : undefined,
|
|
329
337
|
translations: await Promise.all(product.translations.map(async (translation) => {
|
|
330
338
|
return {
|
|
331
339
|
languageCode: translation.languageCode,
|
|
@@ -430,6 +438,7 @@ let ProductImporter = class ProductImporter {
|
|
|
430
438
|
sku: variant.sku,
|
|
431
439
|
},
|
|
432
440
|
withDeleted: true,
|
|
441
|
+
relations: ['facetValues', 'facetValues.facet', 'assets', 'featuredAsset'],
|
|
433
442
|
});
|
|
434
443
|
if (existingVariant?.deletedAt) {
|
|
435
444
|
existingVariant.deletedAt = null;
|
|
@@ -441,10 +450,18 @@ let ProductImporter = class ProductImporter {
|
|
|
441
450
|
console.error('Error while restoring the variant:', error);
|
|
442
451
|
}
|
|
443
452
|
}
|
|
453
|
+
if (existingVariant && updatingStrategy === 'replace') {
|
|
454
|
+
// Remove all assets from the product
|
|
455
|
+
await this.fastImporter.removeAllAssetsFromVariant(existingVariant);
|
|
456
|
+
}
|
|
444
457
|
const variantData = {
|
|
445
458
|
productId: createdProductId,
|
|
446
|
-
|
|
447
|
-
featuredAssetId:
|
|
459
|
+
facetValueIds: updatingStrategy === 'replace' ? [] : undefined,
|
|
460
|
+
featuredAssetId: existingVariant?.featuredAsset
|
|
461
|
+
? undefined
|
|
462
|
+
: variantAssets.length
|
|
463
|
+
? variantAssets[0].id
|
|
464
|
+
: undefined,
|
|
448
465
|
assetIds: variantAssets.map((a) => a.id),
|
|
449
466
|
sku: variant.sku,
|
|
450
467
|
taxCategoryId: this.getMatchingTaxCategoryId(variant.taxCategory, taxCategories.items),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Channel, ChannelService, EntityHydrator, ID, RequestContextService, StockMovementService, TransactionalConnection, TranslatableSaver } from '@vendure/core';
|
|
1
|
+
import { Channel, ChannelService, EntityHydrator, ID, Product, ProductVariant, RequestContextService, StockMovementService, TransactionalConnection, TranslatableSaver } from '@vendure/core';
|
|
2
2
|
import { CreateFacetInput, CreateFacetValueInput, CreateProductInput, CreateProductOptionGroupInput, CreateProductOptionInput, CreateProductVariantInput } from '@vendure/common/lib/generated-types';
|
|
3
3
|
export declare class ExtendedFastImporterService {
|
|
4
4
|
private connection;
|
|
@@ -23,6 +23,8 @@ export declare class ExtendedFastImporterService {
|
|
|
23
23
|
updateProduct(id: ID, input: CreateProductInput & {
|
|
24
24
|
id: ID;
|
|
25
25
|
}): Promise<ID>;
|
|
26
|
+
removeAllAssetsFromProduct(product: Product): Promise<void>;
|
|
27
|
+
removeAllAssetsFromVariant(variant: ProductVariant): Promise<void>;
|
|
26
28
|
createProduct(input: CreateProductInput): Promise<ID>;
|
|
27
29
|
updateProductOptionGroup(input: CreateProductOptionGroupInput & {
|
|
28
30
|
id: ID;
|
|
@@ -63,6 +63,9 @@ let ExtendedFastImporterService = class ExtendedFastImporterService {
|
|
|
63
63
|
beforeSave: async (p) => {
|
|
64
64
|
await this.entityHydrator.hydrate(this.importCtx, p, { relations: ['channels'] });
|
|
65
65
|
p.channels = (0, unique_1.unique)([...p.channels, this.defaultChannel, this.importCtx.channel], 'id');
|
|
66
|
+
if (input.facetValueIds) {
|
|
67
|
+
p.facetValues = input.facetValueIds.map((id) => ({ id }));
|
|
68
|
+
}
|
|
66
69
|
if (input.featuredAssetId) {
|
|
67
70
|
p.featuredAsset = { id: input.featuredAssetId };
|
|
68
71
|
}
|
|
@@ -83,6 +86,20 @@ let ExtendedFastImporterService = class ExtendedFastImporterService {
|
|
|
83
86
|
}
|
|
84
87
|
return product.id;
|
|
85
88
|
}
|
|
89
|
+
async removeAllAssetsFromProduct(product) {
|
|
90
|
+
this.ensureInitialized();
|
|
91
|
+
await this.connection
|
|
92
|
+
.getRepository(this.importCtx, core_1.ProductAsset)
|
|
93
|
+
.delete({ productId: product.id });
|
|
94
|
+
product.featuredAsset = undefined;
|
|
95
|
+
}
|
|
96
|
+
async removeAllAssetsFromVariant(variant) {
|
|
97
|
+
this.ensureInitialized();
|
|
98
|
+
await this.connection
|
|
99
|
+
.getRepository(this.importCtx, core_1.ProductVariantAsset)
|
|
100
|
+
.delete({ productVariantId: variant.id });
|
|
101
|
+
variant.featuredAsset = undefined;
|
|
102
|
+
}
|
|
86
103
|
async createProduct(input) {
|
|
87
104
|
this.ensureInitialized();
|
|
88
105
|
// https://github.com/vendure-ecommerce/vendure/issues/2053
|
|
@@ -310,6 +327,9 @@ let ExtendedFastImporterService = class ExtendedFastImporterService {
|
|
|
310
327
|
if (optionIds && optionIds.length) {
|
|
311
328
|
variant.options = optionIds.map((id) => ({ id }));
|
|
312
329
|
}
|
|
330
|
+
if (input.facetValueIds) {
|
|
331
|
+
variant.facetValues = input.facetValueIds.map((id) => ({ id }));
|
|
332
|
+
}
|
|
313
333
|
variant.product = { id: input.productId };
|
|
314
334
|
variant.taxCategory = { id: input.taxCategoryId };
|
|
315
335
|
if (input.featuredAssetId) {
|
package/dist/types.d.ts
CHANGED
|
@@ -37,5 +37,5 @@ export type JsonAsset = {
|
|
|
37
37
|
type ExportFields = Array<ProductFields | VariantFields>;
|
|
38
38
|
type ProductFields = 'productId' | 'name' | 'slug' | 'description' | 'assets' | 'facets' | 'optionGroups';
|
|
39
39
|
type VariantFields = 'sku' | 'optionValues' | 'price' | 'taxCategory' | 'stockOnHand' | 'trackInventory' | 'variantAssets' | 'variantFacets';
|
|
40
|
-
export type UpdatingStrategy = '
|
|
40
|
+
export type UpdatingStrategy = 'replace' | 'merge';
|
|
41
41
|
export {};
|
|
@@ -3,7 +3,7 @@ import { NotificationService, LocalStorageService } from '@vendure/admin-ui/core
|
|
|
3
3
|
import { TranslateService } from '@ngx-translate/core';
|
|
4
4
|
import { AdminUiConfig } from '@vendure/common/lib/shared-types';
|
|
5
5
|
import { Channel, LanguageCode } from '@vendure/core';
|
|
6
|
-
type UpdatingStrategy = '
|
|
6
|
+
type UpdatingStrategy = 'replace' | 'merge';
|
|
7
7
|
type ImportOptions = {
|
|
8
8
|
updateProductSlug?: string;
|
|
9
9
|
};
|
|
@@ -83,11 +83,11 @@
|
|
|
83
83
|
<input
|
|
84
84
|
type="radio"
|
|
85
85
|
name="updatingStrategy"
|
|
86
|
-
value="
|
|
86
|
+
value="merge"
|
|
87
87
|
[(ngModel)]="updatingStrategy"
|
|
88
88
|
style="width: fit-content"
|
|
89
89
|
/>
|
|
90
|
-
{{ 'product-import.card.
|
|
90
|
+
{{ 'product-import.card.merge' | translate }}
|
|
91
91
|
</label>
|
|
92
92
|
</div>
|
|
93
93
|
<div>
|
|
@@ -95,11 +95,14 @@
|
|
|
95
95
|
<input
|
|
96
96
|
type="radio"
|
|
97
97
|
name="updatingStrategy"
|
|
98
|
-
value="
|
|
98
|
+
value="replace"
|
|
99
99
|
[(ngModel)]="updatingStrategy"
|
|
100
100
|
style="width: fit-content"
|
|
101
101
|
/>
|
|
102
|
-
{{ 'product-import.card.
|
|
102
|
+
{{ 'product-import.card.overwrite' | translate }}<br />
|
|
103
|
+
<span *ngIf="updatingStrategy === 'replace'" style="color: red; font-size: 12px">{{
|
|
104
|
+
'product-import.card.overwrite-warning' | translate
|
|
105
|
+
}}</span>
|
|
103
106
|
</label>
|
|
104
107
|
</div>
|
|
105
108
|
</div>
|
|
@@ -91,6 +91,7 @@ let ProductImportComponent = class ProductImportComponent {
|
|
|
91
91
|
this.selectedFile = null;
|
|
92
92
|
this.validateFile = null;
|
|
93
93
|
this.selectedMainLanguage = undefined;
|
|
94
|
+
this.updatingStrategy = 'merge';
|
|
94
95
|
}
|
|
95
96
|
async validateCsvStructure(file) {
|
|
96
97
|
const baseColumns = ['sku'];
|
|
@@ -7,7 +7,7 @@ import { endsWith, startsWith, size, uniq } from 'lodash'
|
|
|
7
7
|
import { AdminUiConfig } from '@vendure/common/lib/shared-types'
|
|
8
8
|
import { Channel, LanguageCode } from '@vendure/core'
|
|
9
9
|
|
|
10
|
-
type UpdatingStrategy = '
|
|
10
|
+
type UpdatingStrategy = 'replace' | 'merge'
|
|
11
11
|
|
|
12
12
|
type ImportOptions = {
|
|
13
13
|
updateProductSlug?: string
|
|
@@ -117,6 +117,7 @@ export class ProductImportComponent implements OnInit {
|
|
|
117
117
|
this.selectedFile = null
|
|
118
118
|
this.validateFile = null
|
|
119
119
|
this.selectedMainLanguage = undefined
|
|
120
|
+
this.updatingStrategy = 'merge'
|
|
120
121
|
}
|
|
121
122
|
|
|
122
123
|
async validateCsvStructure(file: File): Promise<ValidateReturnType> {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"select-main-language": "Select main language: ",
|
|
11
11
|
"updating-strategy": "Updating strategy for facets and assets: ",
|
|
12
12
|
"overwrite": "Overwrite",
|
|
13
|
+
"overwrite-warning": "Warning: This will remove existing facets and assets from products and variants.",
|
|
13
14
|
"merge": "Merge",
|
|
14
15
|
"main-language-info": "The main language is used as a fallback when translations are missing. It is recommended to select the language that is used the most in your system. The main language will be used to create products, the other languages will be used to fill in translations."
|
|
15
16
|
},
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"select-main-language": "Välj huvudspråk: ",
|
|
11
11
|
"updating-strategy": "Uppdateringsstrategi för etiketter och filer: ",
|
|
12
12
|
"overwrite": "Skriv över",
|
|
13
|
+
"overwrite-warning": "Varning: Detta kommer ta bort befintliga etiketter och filer från produkter och varianter.",
|
|
13
14
|
"merge": "Sammanfoga",
|
|
14
15
|
"main-language-info": "Huvudspråket används som fallback när översättningar saknas. Det rekommenderas att välja det språk som används mest i din kanal. Huvudspråket kommer användas för att skapa upp produkter, de övriga språken kommer användas för att fylla i översättningar."
|
|
15
16
|
},
|
package/package.json
CHANGED