@bytebrand/export-cars 1.7.1 → 1.9.0
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/app.module.js +7 -5
- package/dist/app.module.js.map +1 -1
- package/dist/configs/alleskralle.config.js +3 -1
- package/dist/configs/alleskralle.config.js.map +1 -1
- package/dist/configs/as24.config.js.map +1 -1
- package/dist/configs/autoboerse.config.js +1 -1
- package/dist/configs/autouncle.config.js +1 -1
- package/dist/configs/config.d.ts +3 -1
- package/dist/configs/config.js +6 -4
- package/dist/configs/config.js.map +1 -1
- package/dist/configs/criteo.config.js +2 -1
- package/dist/configs/criteo.config.js.map +1 -1
- package/dist/configs/dasparking.config.js +1 -1
- package/dist/configs/facebook-shop.config.d.ts +5 -0
- package/dist/configs/facebook-shop.config.js +17 -0
- package/dist/configs/facebook-shop.config.js.map +1 -0
- package/dist/configs/index.d.ts +1 -0
- package/dist/configs/index.js +1 -0
- package/dist/configs/index.js.map +1 -1
- package/dist/configs/kleinanzeigefocus.config.js +2 -2
- package/dist/configs/kleinanzeigefocus.config.js.map +1 -1
- package/dist/configs/meinstadt.config.js +0 -1
- package/dist/configs/meinstadt.config.js.map +1 -1
- package/dist/configs/ooyyo.config.js +1 -0
- package/dist/configs/ooyyo.config.js.map +1 -1
- package/dist/constants/modix/index.d.ts +1 -0
- package/dist/constants/modix/index.js +1 -0
- package/dist/constants/modix/index.js.map +1 -1
- package/dist/enums/export-type.enum.d.ts +2 -1
- package/dist/enums/export-type.enum.js +1 -0
- package/dist/enums/export-type.enum.js.map +1 -1
- package/dist/enums/file-types.enum.js +0 -1
- package/dist/enums/file-types.enum.js.map +1 -1
- package/dist/enums/image-type.enum.d.ts +4 -0
- package/dist/enums/image-type.enum.js +9 -0
- package/dist/enums/image-type.enum.js.map +1 -0
- package/dist/enums/index.d.ts +2 -0
- package/dist/enums/index.js +2 -0
- package/dist/enums/index.js.map +1 -1
- package/dist/export.schema.d.ts +6 -2
- package/dist/export.schema.js +4 -0
- package/dist/export.schema.js.map +1 -1
- package/dist/exporters/auto24.exporter.js +1 -1
- package/dist/exporters/auto24.exporter.js.map +1 -1
- package/dist/exporters/facebook-shop.exporter.d.ts +12 -0
- package/dist/exporters/facebook-shop.exporter.js +63 -0
- package/dist/exporters/facebook-shop.exporter.js.map +1 -0
- package/dist/exporters/fb.exporter.js +1 -3
- package/dist/exporters/fb.exporter.js.map +1 -1
- package/dist/exporters/index.d.ts +1 -0
- package/dist/exporters/index.js +1 -0
- package/dist/exporters/index.js.map +1 -1
- package/dist/exporters/modix.exporter.js.map +1 -1
- package/dist/exporters/ooyyo.exporter.js +1 -1
- package/dist/exporters/ooyyo.exporter.js.map +1 -1
- package/dist/formats/facebook-shop.builder.d.ts +10 -0
- package/dist/formats/facebook-shop.builder.js +62 -0
- package/dist/formats/facebook-shop.builder.js.map +1 -0
- package/dist/formats/index.d.ts +1 -0
- package/dist/formats/index.js +1 -0
- package/dist/formats/index.js.map +1 -1
- package/dist/interfaces/export-item.interface.d.ts +26 -0
- package/dist/interfaces/params.interface.d.ts +1 -7
- package/dist/services/{marketing-images.service.d.ts → images.service.d.ts} +9 -5
- package/dist/services/images.service.js +151 -0
- package/dist/services/images.service.js.map +1 -0
- package/dist/services/index.d.ts +1 -1
- package/dist/services/index.js +1 -1
- package/dist/services/index.js.map +1 -1
- package/dist/transformers/auto24.transfomer.d.ts +4 -6
- package/dist/transformers/auto24.transfomer.js +10 -27
- package/dist/transformers/auto24.transfomer.js.map +1 -1
- package/dist/transformers/autouncle.transformer.d.ts +5 -5
- package/dist/transformers/autouncle.transformer.js +10 -34
- package/dist/transformers/autouncle.transformer.js.map +1 -1
- package/dist/transformers/facebook-shop.transformer.d.ts +18 -0
- package/dist/transformers/facebook-shop.transformer.js +96 -0
- package/dist/transformers/facebook-shop.transformer.js.map +1 -0
- package/dist/transformers/fb.transformer.d.ts +2 -3
- package/dist/transformers/fb.transformer.js +8 -26
- package/dist/transformers/fb.transformer.js.map +1 -1
- package/dist/transformers/google.transformer.d.ts +5 -5
- package/dist/transformers/google.transformer.js +10 -26
- package/dist/transformers/google.transformer.js.map +1 -1
- package/dist/transformers/index.d.ts +1 -0
- package/dist/transformers/index.js +1 -0
- package/dist/transformers/index.js.map +1 -1
- package/dist/transformers/meinstadt.transformer.d.ts +1 -1
- package/dist/transformers/meinstadt.transformer.js +3 -4
- package/dist/transformers/meinstadt.transformer.js.map +1 -1
- package/dist/transformers/modix.transformer.d.ts +1 -1
- package/dist/transformers/modix.transformer.js +3 -4
- package/dist/transformers/modix.transformer.js.map +1 -1
- package/dist/transformers/ooyyo.transformer.d.ts +4 -5
- package/dist/transformers/ooyyo.transformer.js +7 -17
- package/dist/transformers/ooyyo.transformer.js.map +1 -1
- package/dist/transformers/rubrikk.transformer.d.ts +4 -4
- package/dist/transformers/rubrikk.transformer.js +5 -13
- package/dist/transformers/rubrikk.transformer.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/app.module.ts +6 -12
- package/src/configs/alleskralle.config.ts +3 -1
- package/src/configs/as24.config.ts +1 -1
- package/src/configs/auto24.config.ts +1 -1
- package/src/configs/autoboerse.config.ts +2 -2
- package/src/configs/autouncle.config.ts +1 -1
- package/src/configs/config.ts +3 -2
- package/src/configs/criteo.config.ts +3 -2
- package/src/configs/dasparking.config.ts +1 -1
- package/src/configs/{kleinanzeigefocus.config.ts → facebook-shop.config.ts} +3 -3
- package/src/configs/index.ts +1 -0
- package/src/configs/kleinanzeigeFocus.config.ts +14 -0
- package/src/configs/meinstadt.config.ts +1 -1
- package/src/configs/ooyyo.config.ts +2 -1
- package/src/constants/modix/index.ts +1 -0
- package/src/enums/export-type.enum.ts +7 -6
- package/src/enums/file-types.enum.ts +1 -1
- package/src/enums/image-type.enum.ts +4 -0
- package/src/enums/index.ts +2 -0
- package/src/export.schema.ts +8 -3
- package/src/exporters/auto24.exporter.ts +2 -4
- package/src/exporters/facebook-shop.exporter.ts +51 -0
- package/src/exporters/fb.exporter.ts +6 -6
- package/src/exporters/index.ts +1 -0
- package/src/exporters/modix.exporter.ts +6 -5
- package/src/exporters/ooyyo.exporter.ts +3 -4
- package/src/formats/facebook-shop.builder.ts +69 -0
- package/src/formats/index.ts +1 -0
- package/src/interfaces/export-item.interface.ts +26 -0
- package/src/interfaces/params.interface.ts +1 -7
- package/src/services/images.service.ts +161 -0
- package/src/services/index.ts +1 -2
- package/src/transformers/auto24.transfomer.ts +8 -31
- package/src/transformers/autouncle.transformer.ts +9 -35
- package/src/transformers/facebook-shop.transformer.ts +94 -0
- package/src/transformers/fb.transformer.ts +16 -44
- package/src/transformers/google.transformer.ts +10 -28
- package/src/transformers/index.ts +1 -0
- package/src/transformers/meinstadt.transformer.ts +2 -3
- package/src/transformers/modix.transformer.ts +19 -10
- package/src/transformers/ooyyo.transformer.ts +4 -18
- package/src/transformers/rubrikk.transformer.ts +5 -16
- package/dist/services/marketing-images.service.js +0 -58
- package/dist/services/marketing-images.service.js.map +0 -1
- package/src/services/marketing-images.service.ts +0 -70
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { Injectable } from '@nestjs/common';
|
|
2
|
+
import { DataSchemes } from '@bytebrand/car-schema';
|
|
3
|
+
import { ImboImageResponseInterface } from '@bytebrand/chunkable';
|
|
4
|
+
import { get, toString } from 'lodash';
|
|
5
|
+
import { isNotEmptyArray } from '../utils/validator.utils';
|
|
6
|
+
import { ConfigService } from './config.service';
|
|
7
|
+
import { ImageType } from '../enums';
|
|
8
|
+
import { MarketingImageConfigInterface, MarketingImageConfigsInterface } from '@bytebrand/autode-request';
|
|
9
|
+
import { UserService } from './user.service';
|
|
10
|
+
import { FB_MAX_IMAGE_COUNT_FOR_DEAFULT } from '../constants/fb.constants';
|
|
11
|
+
|
|
12
|
+
@Injectable()
|
|
13
|
+
export class ImagesService {
|
|
14
|
+
constructor(private readonly configService: ConfigService, private readonly userService: UserService) {}
|
|
15
|
+
|
|
16
|
+
async getImages(
|
|
17
|
+
car: DataSchemes.Car,
|
|
18
|
+
images: ImboImageResponseInterface[],
|
|
19
|
+
imageType: ImageType,
|
|
20
|
+
): Promise<Array<string>> {
|
|
21
|
+
if (imageType === ImageType.default) {
|
|
22
|
+
return this.getDefaultImages(car, images);
|
|
23
|
+
} else {
|
|
24
|
+
const carId = toString(get(car, '_id', ''));
|
|
25
|
+
return await this.getMarketingImages(images, carId);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
getDefaultImages(car: DataSchemes.Car, images: ImboImageResponseInterface[]): Array<string> {
|
|
30
|
+
const defaultImages = [
|
|
31
|
+
'https://images.auto.de/carimage/noimage/7pNvWELuWhZX/large-cached.jpeg',
|
|
32
|
+
'https://images.auto.de/carimage/noimage/GvyXmrpaf1D6/large-cached.jpeg',
|
|
33
|
+
'https://images.auto.de/carimage/noimage/gY1zF8PXzH2W/large-cached.jpeg',
|
|
34
|
+
'https://images.auto.de/carimage/noimage/pFyfBsqBHEso/large-cached.jpeg',
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
if (!isNotEmptyArray(images)) {
|
|
38
|
+
return defaultImages;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const firstImageId = get(car, 'metaData.mainImageId', null);
|
|
42
|
+
const secondImageId = get(car, 'metaData.secImageId', null);
|
|
43
|
+
const thirdImageId = get(car, 'metaData.thirdImageId', null);
|
|
44
|
+
|
|
45
|
+
if (firstImageId) {
|
|
46
|
+
images.forEach((image, index) => {
|
|
47
|
+
if (firstImageId === image.imageIdentifier) {
|
|
48
|
+
const tmp = images[index];
|
|
49
|
+
images[index] = images[0];
|
|
50
|
+
images[0] = tmp;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (secondImageId) {
|
|
56
|
+
images.forEach((image, index) => {
|
|
57
|
+
if (secondImageId === image.imageIdentifier) {
|
|
58
|
+
const tmp = images[index];
|
|
59
|
+
images[index] = images[1];
|
|
60
|
+
images[1] = tmp;
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (thirdImageId) {
|
|
66
|
+
images.forEach((image, index) => {
|
|
67
|
+
if (thirdImageId === image.imageIdentifier) {
|
|
68
|
+
const tmp = images[index];
|
|
69
|
+
images[index] = images[2];
|
|
70
|
+
images[2] = tmp;
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const carId = toString(get(car, '_id', ''));
|
|
76
|
+
|
|
77
|
+
const transformedImages = this.generateImageLinks(images, carId);
|
|
78
|
+
if (transformedImages.length < 17) {
|
|
79
|
+
transformedImages.push(...defaultImages);
|
|
80
|
+
}
|
|
81
|
+
return transformedImages;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
generateImageLinks(images: ImboImageResponseInterface[], carId: string) {
|
|
85
|
+
return images.map((image: ImboImageResponseInterface) => {
|
|
86
|
+
return `${this.configService.config.baseImageUrl}/carimage/${carId}/${image.imageIdentifier}/large`;
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async getMarketingImages(images: any, carId: string): Promise<string[]> {
|
|
91
|
+
const imageUrl = this.configService.config.imageUrl;
|
|
92
|
+
const transformedImages = this.transformImagesArrayIntoObject(images);
|
|
93
|
+
const configs = this.configService.config.isCriteo
|
|
94
|
+
? await this.userService.getMarketingImageConfig(this.configService.config.criteoMarketingImagesConfigId)
|
|
95
|
+
: ((await this.getMarketingImageConfigs()) as any);
|
|
96
|
+
const marketingImageConfigs = this.transform(configs);
|
|
97
|
+
|
|
98
|
+
const defImages = [
|
|
99
|
+
{ url: 'https://images.auto.de/carimage/noimage/7pNvWELuWhZX/large-cached.jpeg' },
|
|
100
|
+
{ url: 'https://images.auto.de/carimage/noimage/GvyXmrpaf1D6/large-cached.jpeg' },
|
|
101
|
+
{ url: 'https://images.auto.de/carimage/noimage/gY1zF8PXzH2W/large-cached.jpeg' },
|
|
102
|
+
{ url: 'https://images.auto.de/carimage/noimage/pFyfBsqBHEso/large-cached.jpeg' },
|
|
103
|
+
];
|
|
104
|
+
|
|
105
|
+
const imageUrls = [];
|
|
106
|
+
|
|
107
|
+
for (let i = 0; i < marketingImageConfigs.length; i++) {
|
|
108
|
+
const marketingImage = marketingImageConfigs[i];
|
|
109
|
+
for (let i = 0; i < marketingImage.marketingImageCodes.length; i++) {
|
|
110
|
+
const imageCode = marketingImage.marketingImageCodes[i];
|
|
111
|
+
const imageId = transformedImages[imageCode];
|
|
112
|
+
if (imageId) {
|
|
113
|
+
imageUrls.push(this.getImagePathWithExtenstion(imageUrl, carId, imageId, configs));
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (imageUrls.length < FB_MAX_IMAGE_COUNT_FOR_DEAFULT) {
|
|
119
|
+
imageUrls.push(...defImages);
|
|
120
|
+
}
|
|
121
|
+
return imageUrls;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async getMarketingImageConfigs(): Promise<MarketingImageConfigsInterface> {
|
|
125
|
+
const configs = await this.userService.getMarketingImageConfigs();
|
|
126
|
+
const { id } = configs.find(config => config.channelCode.includes(this.configService.config.exportType));
|
|
127
|
+
|
|
128
|
+
return this.userService.getMarketingImageConfig(id);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
private transformImagesArrayIntoObject(images: { [imageCode: string]: string }[]) {
|
|
132
|
+
const result: { [imageCode: string]: string } = {};
|
|
133
|
+
images.forEach(image => {
|
|
134
|
+
const imageCode = image.imageCodePredicted.split('-')[0];
|
|
135
|
+
result[imageCode] = image.imageIdentifier;
|
|
136
|
+
});
|
|
137
|
+
return result;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
private transform(config: MarketingImageConfigInterface): { marketingImageCodes: string[] }[] {
|
|
141
|
+
return config.marketingImages.map(marketingImage => {
|
|
142
|
+
return {
|
|
143
|
+
marketingImageCodes: marketingImage.imageCodes,
|
|
144
|
+
};
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
protected getChannelPath(imageUrl: string, carId: string): string {
|
|
149
|
+
return `${imageUrl}/${[carId[0], carId[1], carId[2], carId].join('/')}`;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
protected getImagePathWithExtenstion(
|
|
153
|
+
imageUrl: string,
|
|
154
|
+
carId: string,
|
|
155
|
+
imageId: string,
|
|
156
|
+
config: MarketingImageConfigsInterface,
|
|
157
|
+
): string {
|
|
158
|
+
const { channelCode, imageExtension } = config;
|
|
159
|
+
return `${this.getChannelPath(imageUrl, carId)}/${channelCode.replace(/ /g, '-')}-${imageId}.${imageExtension}`;
|
|
160
|
+
}
|
|
161
|
+
}
|
package/src/services/index.ts
CHANGED
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
import { Translator } from '@bytebrand/schema-tools';
|
|
2
2
|
import { de } from '@bytebrand/i18n-dictionaries';
|
|
3
|
-
import { get,
|
|
3
|
+
import { get, isEmpty, isNil, toString } from 'lodash';
|
|
4
4
|
import * as moment from 'moment';
|
|
5
5
|
import { DataSchemes } from '@bytebrand/car-schema';
|
|
6
6
|
import { ImboImageResponseInterface } from '@bytebrand/chunkable';
|
|
7
7
|
import { Auto24XmlItem } from '../interfaces';
|
|
8
8
|
import { Injectable } from '@nestjs/common';
|
|
9
|
-
import { ConfigService } from '../services
|
|
9
|
+
import { ConfigService, ImagesService } from '../services';
|
|
10
10
|
import { isNotEmptyArray } from '../utils/validator.utils';
|
|
11
|
+
import { ImageType } from '../enums';
|
|
11
12
|
|
|
12
13
|
@Injectable()
|
|
13
14
|
export class Auto24Transformer {
|
|
14
15
|
private translator: Translator;
|
|
15
16
|
|
|
16
|
-
constructor(private configService: ConfigService) {
|
|
17
|
+
constructor(private configService: ConfigService, private readonly imageService: ImagesService) {
|
|
17
18
|
this.translator = new Translator(de);
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
transform(car: DataSchemes.Car, imboImages: ImboImageResponseInterface[]): Auto24XmlItem {
|
|
21
|
+
async transform(car: DataSchemes.Car, imboImages: ImboImageResponseInterface[]): Promise<Auto24XmlItem> {
|
|
21
22
|
const carId = toString(get(car, '_id', ''));
|
|
22
|
-
|
|
23
|
+
const transformedImages = await this.imageService.getImages(car, imboImages, ImageType.default);
|
|
23
24
|
let userlink = `https://www.${this.configService.config.domain}/search/vehicle/${carId}`;
|
|
24
25
|
if (this.configService.config.campaign) {
|
|
25
26
|
userlink += `?source=classifieds&medium=listing&campaign=${this.configService.config.campaign}`;
|
|
@@ -37,9 +38,9 @@ export class Auto24Transformer {
|
|
|
37
38
|
consumptionK: toString(get(car, 'consumption.consumptionCombined', '')),
|
|
38
39
|
co2: toString(get(car, 'environmentEmissions.co2', '')),
|
|
39
40
|
efficiencyclass: this.translateSelector(get(car, 'environmentEmissions.energyEfficiencyClass', '')),
|
|
40
|
-
image:
|
|
41
|
+
image: transformedImages[0],
|
|
41
42
|
registration: this.getRegistrationField(get(car, 'mainData.firstRegistration') as number),
|
|
42
|
-
images:
|
|
43
|
+
images: transformedImages,
|
|
43
44
|
price: toString(get(car, 'price.currentSalesPrice', '')),
|
|
44
45
|
power: toString(get(car, 'engineData.powerKW', '')),
|
|
45
46
|
zip: toString(get(car, 'location.zipCode', '')),
|
|
@@ -132,28 +133,4 @@ export class Auto24Transformer {
|
|
|
132
133
|
})
|
|
133
134
|
.join(', ');
|
|
134
135
|
}
|
|
135
|
-
|
|
136
|
-
private getImagesField(carId: string, images: ImboImageResponseInterface[]): string[] {
|
|
137
|
-
if (isNotEmptyArray(images)) {
|
|
138
|
-
return images.map((image: ImboImageResponseInterface) => {
|
|
139
|
-
return this.buildLargeImageUrl(carId, image.imageIdentifier);
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
return [];
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
private getImageField(carId: string, mainImageId: string, images: ImboImageResponseInterface[]): string {
|
|
146
|
-
if (isNil(mainImageId) || isEmpty(mainImageId)) {
|
|
147
|
-
if (isNotEmptyArray(images)) {
|
|
148
|
-
const firstImageId = first(images);
|
|
149
|
-
return this.buildLargeImageUrl(carId, firstImageId.imageIdentifier);
|
|
150
|
-
}
|
|
151
|
-
return '';
|
|
152
|
-
}
|
|
153
|
-
return this.buildLargeImageUrl(carId, mainImageId);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
private buildLargeImageUrl(carId: string, imageId: string): string {
|
|
157
|
-
return `${this.configService.config.imageUrl}/carimage/${carId}/${imageId}/large`;
|
|
158
|
-
}
|
|
159
136
|
}
|
|
@@ -5,18 +5,18 @@ import * as moment from 'moment';
|
|
|
5
5
|
import { DataSchemes } from '@bytebrand/car-schema';
|
|
6
6
|
import { DePostalCodesService } from '@bytebrand/car-basic-data-scope';
|
|
7
7
|
import { DePostalCodesEntryInterface } from '@bytebrand/car-basic-data-scope/dist/interfaces/DePostalCodesInterface';
|
|
8
|
-
import { ConfigService } from '../services
|
|
8
|
+
import { ConfigService, ImagesService } from '../services';
|
|
9
9
|
import { Injectable } from '@nestjs/common';
|
|
10
10
|
import { DEFAULT_ADDR1, DEFAULT_CITY, DEFAULT_ZIP, MIN_MILEAGES } from '../constants/autouncle.contants';
|
|
11
11
|
import { AutouncleJsonItem } from '../interfaces';
|
|
12
|
-
import {
|
|
12
|
+
import { ImboImageResponseInterface } from '@bytebrand/chunkable';
|
|
13
13
|
|
|
14
14
|
@Injectable()
|
|
15
15
|
export class AutouncleTransformer {
|
|
16
16
|
private translator: TranslatorExtended;
|
|
17
17
|
private postalCodesService: DePostalCodesService;
|
|
18
18
|
|
|
19
|
-
constructor(private configService: ConfigService) {
|
|
19
|
+
constructor(private configService: ConfigService, private imageService: ImagesService) {
|
|
20
20
|
const dict = { ...de, ...deVehicleProps, ...deVehicleDetailsPage };
|
|
21
21
|
this.translator = new TranslatorExtended(dict);
|
|
22
22
|
this.postalCodesService = DePostalCodesService.getInstance();
|
|
@@ -28,7 +28,7 @@ export class AutouncleTransformer {
|
|
|
28
28
|
owner,
|
|
29
29
|
}: {
|
|
30
30
|
car: DataSchemes.Car;
|
|
31
|
-
images:
|
|
31
|
+
images: ImboImageResponseInterface[];
|
|
32
32
|
metadata?: unknown;
|
|
33
33
|
owner: unknown;
|
|
34
34
|
}): Promise<AutouncleJsonItem> {
|
|
@@ -61,7 +61,7 @@ export class AutouncleTransformer {
|
|
|
61
61
|
seller_name: 'auto.de',
|
|
62
62
|
seller_id: toString(get(car, 'metaData.ownerId', '')),
|
|
63
63
|
description: toString(get(car, 'offer.offerDescription', '')),
|
|
64
|
-
images: this.getImagesField(
|
|
64
|
+
images: this.getImagesField(car, images),
|
|
65
65
|
fuel_economy: toString(get(car, 'consumption.consumptionCombined', '')),
|
|
66
66
|
co2_emission: toString(get(car, 'environmentEmissions.co2', '')),
|
|
67
67
|
co2_effiency_class: toString(get(car, 'environmentEmissions.energyEfficiencyClass', '')),
|
|
@@ -230,35 +230,9 @@ export class AutouncleTransformer {
|
|
|
230
230
|
return '';
|
|
231
231
|
}
|
|
232
232
|
|
|
233
|
-
private getImagesField(
|
|
234
|
-
|
|
235
|
-
{ url
|
|
236
|
-
|
|
237
|
-
{ url: 'https://images.auto.de/carimage/noimage/gY1zF8PXzH2W/large-cached.jpeg' },
|
|
238
|
-
{ url: 'https://images.auto.de/carimage/noimage/pFyfBsqBHEso/large-cached.jpeg' },
|
|
239
|
-
];
|
|
240
|
-
if (isNotEmptyArray(images)) {
|
|
241
|
-
const imageList = images.sort(this.setMainImageFirst(mainImageId)).map((image: any) => {
|
|
242
|
-
return { url: this.buildLargeImageUrl(carId, image.imageIdentifier) };
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
if (imageList.length < 17) {
|
|
246
|
-
imageList.push(...defImages);
|
|
247
|
-
}
|
|
248
|
-
return imageList;
|
|
249
|
-
}
|
|
250
|
-
return defImages;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
private buildLargeImageUrl(carId: string, imageId: string): string {
|
|
254
|
-
return `${this.configService.config.imageUrl}/carimage/${carId}/${imageId}/large`;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
private setMainImageFirst(mainImageId: string): (current: any, next: any) => number {
|
|
258
|
-
return (current: any, next: any): number => {
|
|
259
|
-
if (current.imageIdentifier === mainImageId) return -1;
|
|
260
|
-
if (next.imageIdentifier === mainImageId) return 1;
|
|
261
|
-
return 0;
|
|
262
|
-
};
|
|
233
|
+
private getImagesField(car: DataSchemes.Car, images: ImboImageResponseInterface[]): { url: string }[] {
|
|
234
|
+
return this.imageService.getDefaultImages(car, images).map(url => {
|
|
235
|
+
return { url };
|
|
236
|
+
});
|
|
263
237
|
}
|
|
264
238
|
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { Injectable } from '@nestjs/common';
|
|
2
|
+
|
|
3
|
+
import { escape, get, join, round, toString, trim } from 'lodash';
|
|
4
|
+
|
|
5
|
+
import { de, deVehicleDetailsPage, deVehicleProps } from '@bytebrand/i18n-dictionaries';
|
|
6
|
+
import { TranslatorExtended } from '@bytebrand/schema-tools';
|
|
7
|
+
import { DataSchemes } from '@bytebrand/car-schema';
|
|
8
|
+
|
|
9
|
+
import { FacebookShopItem } from '../interfaces';
|
|
10
|
+
import { ConfigService } from '../services';
|
|
11
|
+
import { Description } from '../interfaces/description.interface';
|
|
12
|
+
import { FbDescription } from './fb-description.transformer';
|
|
13
|
+
import { FbEquipment } from './fb-equipment.transformer';
|
|
14
|
+
|
|
15
|
+
@Injectable()
|
|
16
|
+
export class FacebookShopTransformer {
|
|
17
|
+
private translator: TranslatorExtended;
|
|
18
|
+
|
|
19
|
+
constructor(private readonly configService: ConfigService) {
|
|
20
|
+
const dict = { ...de, ...deVehicleProps, ...deVehicleDetailsPage };
|
|
21
|
+
this.translator = new TranslatorExtended(dict);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async transform({ car }: { car: DataSchemes.Car }): Promise<FacebookShopItem> {
|
|
25
|
+
return {
|
|
26
|
+
id: { value: get(car, 'metaData.vehicleId'), isGoogle: true },
|
|
27
|
+
title: { value: this.getTitle(car), isGoogle: true },
|
|
28
|
+
description: { value: this.getDescription(car), isGoogle: true },
|
|
29
|
+
availability: { value: 'in stock', isGoogle: true },
|
|
30
|
+
condition: { value: this.getCondition(car), isGoogle: true },
|
|
31
|
+
price: { value: this.getPrice(car), isGoogle: true },
|
|
32
|
+
link: { value: this.getCarLink(car), isGoogle: true },
|
|
33
|
+
image_link: { value: this.getImageLink(car), isGoogle: true },
|
|
34
|
+
brand: { value: get(car, 'mainData.make', ''), isGoogle: true },
|
|
35
|
+
additional_image_link: { value: this.getImageLink(car), isGoogle: false },
|
|
36
|
+
quantity_to_sell_on_facebook: { value: 1, isGoogle: true },
|
|
37
|
+
google_product_category: { value: '916', isGoogle: true },
|
|
38
|
+
sale_price: { value: this.getPrice(car), isGoogle: true },
|
|
39
|
+
status: { value: 'active', isGoogle: true },
|
|
40
|
+
color: { value: this.getColor(car), isGoogle: false },
|
|
41
|
+
product_type: {
|
|
42
|
+
value: 'Vehicles & Parts > Vehicles > Motor Vehicles > Cars, Trucks & Vans',
|
|
43
|
+
isGoogle: true,
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private getTitle(car: DataSchemes.Car): string {
|
|
49
|
+
const year = toString(get(car, 'mainData.constructionYear', ''));
|
|
50
|
+
const make = toString(get(car, 'mainData.make', ''));
|
|
51
|
+
const model = toString(get(car, 'mainData.model', ''));
|
|
52
|
+
const subModel = toString(get(car, 'mainData.subModel', ''));
|
|
53
|
+
return trim(escape(join([year, make, model, subModel], ' ')));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private getCondition(car: DataSchemes.Car): string {
|
|
57
|
+
const available = {
|
|
58
|
+
selector_condition_new: 'New',
|
|
59
|
+
selector_condition_used: 'Used',
|
|
60
|
+
selector_unknown: 'New',
|
|
61
|
+
};
|
|
62
|
+
const condition = get(car, 'mainData.condition', 'selector_unknown');
|
|
63
|
+
return get(available, condition);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private getCarLink(car: DataSchemes.Car): string {
|
|
67
|
+
return `https://${this.configService.config.domain}/search/vehicle/${car._id}`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private getPrice(car: DataSchemes.Car): string {
|
|
71
|
+
const price = get(car, 'price.currentSalesPrice', 0);
|
|
72
|
+
return `${round(price, 2)} EUR`;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
private getColor(car: DataSchemes.Car): string {
|
|
76
|
+
let colorSelection = get(car, 'exterior.exteriorColor', 'selector_unknown');
|
|
77
|
+
if (!colorSelection || colorSelection === 'selector_unknown') {
|
|
78
|
+
colorSelection = 'selector_unknown';
|
|
79
|
+
}
|
|
80
|
+
return this.translator.translateVal(colorSelection);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private getDescription(car: DataSchemes.Car): Description[] {
|
|
84
|
+
return FbDescription.create(car, this.translator, new FbEquipment()).getDescriptionArray();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
//todo: move to image service
|
|
88
|
+
private getImageLink(car: DataSchemes.Car): string {
|
|
89
|
+
const mainImageId = get(car, 'metaData.mainImageId', '');
|
|
90
|
+
return mainImageId
|
|
91
|
+
? `${this.configService.config.baseImageUrl}/carimage/${car._id}/${mainImageId}/large-cached.webp`
|
|
92
|
+
: `${this.configService.config.baseImageUrl}/carimage/noimage/7pNvWELuWhZX/large-cached.jpeg`;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -1,28 +1,27 @@
|
|
|
1
1
|
import { TranslatorExtended } from '@bytebrand/schema-tools';
|
|
2
2
|
import { de, deVehicleDetailsPage, deVehicleProps } from '@bytebrand/i18n-dictionaries';
|
|
3
3
|
import {
|
|
4
|
+
escape,
|
|
5
|
+
findIndex,
|
|
4
6
|
get,
|
|
5
|
-
|
|
7
|
+
includes,
|
|
8
|
+
isArray,
|
|
9
|
+
isBoolean,
|
|
6
10
|
isEmpty,
|
|
7
|
-
|
|
11
|
+
isString,
|
|
8
12
|
join,
|
|
9
|
-
escape,
|
|
10
13
|
toSafeInteger,
|
|
14
|
+
toString,
|
|
15
|
+
trim,
|
|
11
16
|
truncate,
|
|
12
|
-
isBoolean,
|
|
13
|
-
isString,
|
|
14
|
-
isArray,
|
|
15
|
-
includes,
|
|
16
|
-
findIndex,
|
|
17
17
|
} from 'lodash';
|
|
18
18
|
import * as moment from 'moment';
|
|
19
19
|
import { DataSchemes } from '@bytebrand/car-schema';
|
|
20
20
|
import { DePostalCodesService } from '@bytebrand/car-basic-data-scope';
|
|
21
21
|
import { DePostalCodesEntryInterface } from '@bytebrand/car-basic-data-scope/dist/interfaces/DePostalCodesInterface';
|
|
22
|
-
import {
|
|
23
|
-
import { ConfigService } from '../services/config.service';
|
|
22
|
+
import { ConfigService, ImagesService } from '../services';
|
|
24
23
|
import { ImboImageResponseInterface } from '@bytebrand/chunkable';
|
|
25
|
-
import {
|
|
24
|
+
import { isValidVin } from '../utils/validator.utils';
|
|
26
25
|
import { Injectable } from '@nestjs/common';
|
|
27
26
|
import { FbDescription } from './fb-description.transformer';
|
|
28
27
|
import { Description } from '../interfaces/description.interface';
|
|
@@ -31,24 +30,21 @@ import {
|
|
|
31
30
|
DEFAULT_ADDR1,
|
|
32
31
|
DEFAULT_CITY,
|
|
33
32
|
DEFAULT_ZIP,
|
|
34
|
-
FB_MAX_IMAGE_COUNT_FOR_DEAFULT,
|
|
35
33
|
FB_MAX_TRIM_LENGTH,
|
|
36
34
|
FB_MIN_MILEAGES,
|
|
37
35
|
TIMESTAMP_FIRST_YEAR,
|
|
38
36
|
} from '../constants/fb.constants';
|
|
39
37
|
import { UserService } from 'src/services';
|
|
38
|
+
import { ImageType } from '../enums';
|
|
40
39
|
|
|
41
40
|
@Injectable()
|
|
42
41
|
export class FbTransformer {
|
|
43
42
|
private translator: TranslatorExtended;
|
|
44
43
|
private postalCodesService: DePostalCodesService;
|
|
45
|
-
private
|
|
44
|
+
private imagesService: ImagesService;
|
|
46
45
|
|
|
47
|
-
constructor(
|
|
48
|
-
|
|
49
|
-
private readonly userService: UserService
|
|
50
|
-
) {
|
|
51
|
-
this.marketingImages = new MarketingImagesService(configService, userService);
|
|
46
|
+
constructor(private readonly configService: ConfigService, private readonly userService: UserService) {
|
|
47
|
+
this.imagesService = new ImagesService(configService, userService);
|
|
52
48
|
const dict = { ...de, ...deVehicleProps, ...deVehicleDetailsPage };
|
|
53
49
|
this.translator = new TranslatorExtended(dict);
|
|
54
50
|
this.postalCodesService = DePostalCodesService.getInstance();
|
|
@@ -81,7 +77,7 @@ export class FbTransformer {
|
|
|
81
77
|
make: toString(get(car, 'mainData.make', '')),
|
|
82
78
|
model: toString(get(car, 'mainData.model', '')),
|
|
83
79
|
trim: this.getTrim(car),
|
|
84
|
-
image: await this.
|
|
80
|
+
image: await this.imagesService.getImages(car, images, ImageType.marketing),
|
|
85
81
|
year: toString(year),
|
|
86
82
|
mileage: {
|
|
87
83
|
value: this.getMileage(car),
|
|
@@ -152,15 +148,13 @@ export class FbTransformer {
|
|
|
152
148
|
dealer_email: string;
|
|
153
149
|
dealer_phone: string;
|
|
154
150
|
} {
|
|
155
|
-
|
|
151
|
+
return {
|
|
156
152
|
dealer_communication_channel: 'LEAD_FORM',
|
|
157
153
|
dealer_id: get(car, 'metaData.ownerId'),
|
|
158
154
|
dealer_privacy_policy_url: 'https://www.auto.de/einwilligungserklaerung-datenschutz-agb/',
|
|
159
155
|
dealer_email: 'auto@auto.de',
|
|
160
156
|
dealer_phone: '+498000008300',
|
|
161
157
|
};
|
|
162
|
-
|
|
163
|
-
return items;
|
|
164
158
|
}
|
|
165
159
|
|
|
166
160
|
private getTitle(car: DataSchemes.Car): string {
|
|
@@ -372,28 +366,6 @@ export class FbTransformer {
|
|
|
372
366
|
return mileage <= FB_MIN_MILEAGES ? FB_MIN_MILEAGES + 1 : mileage;
|
|
373
367
|
}
|
|
374
368
|
|
|
375
|
-
private async getImagesField(
|
|
376
|
-
carId: string,
|
|
377
|
-
_mainImageId: string,
|
|
378
|
-
images: ImboImageResponseInterface[],
|
|
379
|
-
): Promise<{ url: string }[]> {
|
|
380
|
-
const defImages = [
|
|
381
|
-
{ url: 'https://images.auto.de/carimage/noimage/7pNvWELuWhZX/large-cached.jpeg' },
|
|
382
|
-
{ url: 'https://images.auto.de/carimage/noimage/GvyXmrpaf1D6/large-cached.jpeg' },
|
|
383
|
-
{ url: 'https://images.auto.de/carimage/noimage/gY1zF8PXzH2W/large-cached.jpeg' },
|
|
384
|
-
{ url: 'https://images.auto.de/carimage/noimage/pFyfBsqBHEso/large-cached.jpeg' },
|
|
385
|
-
];
|
|
386
|
-
if (isNotEmptyArray(images)) {
|
|
387
|
-
const imageList = await this.marketingImages.getImagesUrl(images, this.configService.config.imageUrl, carId);
|
|
388
|
-
|
|
389
|
-
if (imageList.length < FB_MAX_IMAGE_COUNT_FOR_DEAFULT) {
|
|
390
|
-
imageList.push(...defImages);
|
|
391
|
-
}
|
|
392
|
-
return imageList;
|
|
393
|
-
}
|
|
394
|
-
return defImages;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
369
|
private getHighlights(car: DataSchemes.Car): { type: unknown; value: unknown }[] {
|
|
398
370
|
const facebookFeatures = [
|
|
399
371
|
{ key: 'assistants.abs', type: 'abs_brakes', value: 'ABS' },
|
|
@@ -1,25 +1,28 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { escape, get, join, round, toString, trim } from 'lodash';
|
|
2
2
|
import { CarDescriptionFactory, DescriptionTypeEnum } from '@bytebrand/car-description';
|
|
3
3
|
import { DataSchemes } from '@bytebrand/car-schema';
|
|
4
4
|
import { TranslatorExtended } from '@bytebrand/schema-tools';
|
|
5
5
|
import { de, deVehicleDetailsPage, deVehicleProps } from '@bytebrand/i18n-dictionaries';
|
|
6
6
|
import { Injectable } from '@nestjs/common';
|
|
7
|
-
import { UserService } from '../services
|
|
8
|
-
import { ConfigService } from '../services/config.service';
|
|
7
|
+
import { ConfigService, ImagesService, UserService } from '../services';
|
|
9
8
|
import { GoogleXmlItem } from '../interfaces';
|
|
9
|
+
import { ImageType } from '../enums';
|
|
10
10
|
|
|
11
11
|
@Injectable()
|
|
12
12
|
export class GoogleTransformer {
|
|
13
13
|
private translator: TranslatorExtended;
|
|
14
14
|
|
|
15
|
-
constructor(
|
|
15
|
+
constructor(
|
|
16
|
+
private userService: UserService,
|
|
17
|
+
private configService: ConfigService,
|
|
18
|
+
private imageService: ImagesService,
|
|
19
|
+
) {
|
|
16
20
|
const dict = { ...de, ...deVehicleProps, ...deVehicleDetailsPage };
|
|
17
21
|
this.translator = new TranslatorExtended(dict);
|
|
18
22
|
}
|
|
19
23
|
|
|
20
|
-
async transform({ car }: { car: DataSchemes.Car }): Promise<GoogleXmlItem> {
|
|
24
|
+
async transform({ car, images }: { car: DataSchemes.Car; images: Array<any> }): Promise<GoogleXmlItem> {
|
|
21
25
|
const carId = toString(get(car, '_id', ''));
|
|
22
|
-
const mainImageId = get(car, 'metaData.mainImageId', '');
|
|
23
26
|
|
|
24
27
|
return {
|
|
25
28
|
id: carId,
|
|
@@ -28,7 +31,7 @@ export class GoogleTransformer {
|
|
|
28
31
|
google_product_category: this.getBreadcrumbs(car),
|
|
29
32
|
product_type: this.getCategory(car),
|
|
30
33
|
link: this.getLink(car),
|
|
31
|
-
image_link: await this.
|
|
34
|
+
image_link: await this.imageService.getImages(car, images, ImageType.marketing)[0],
|
|
32
35
|
condition: this.mapState(car),
|
|
33
36
|
availability: this.getAvailability(car),
|
|
34
37
|
brand: get(car, 'mainData.make', ''),
|
|
@@ -98,27 +101,6 @@ export class GoogleTransformer {
|
|
|
98
101
|
return this.translator.translateVal(colorSelection);
|
|
99
102
|
}
|
|
100
103
|
|
|
101
|
-
private async buildLargeImageUrl(carId: string, imageId: string): Promise<string> {
|
|
102
|
-
if (this.configService.config.isCriteo) {
|
|
103
|
-
try {
|
|
104
|
-
const criteoConfig = await this.userService.getMarketingImageConfig(this.configService.config.criteoMarketingImagesConfigId);
|
|
105
|
-
return imageId
|
|
106
|
-
? `${this.configService.config.imageUrl}/generated_images/${[carId[0], carId[1], carId[2], carId].join(
|
|
107
|
-
'/',
|
|
108
|
-
)}/criteo-${imageId}.${criteoConfig.imageExtension}`
|
|
109
|
-
: 'https://images.auto.de/carimage/noimage/7pNvWELuWhZX/large';
|
|
110
|
-
} catch (e) {
|
|
111
|
-
console.log('Error: Failed to get criteoConfig');
|
|
112
|
-
return imageId
|
|
113
|
-
? `${this.configService.config.imageUrl}/carimage/${carId}/${imageId}/large`
|
|
114
|
-
: 'https://images.auto.de/carimage/noimage/7pNvWELuWhZX/large';
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
return imageId
|
|
118
|
-
? `${this.configService.config.imageUrl}/carimage/${carId}/${imageId}/large`
|
|
119
|
-
: 'https://images.auto.de/carimage/noimage/7pNvWELuWhZX/large';
|
|
120
|
-
}
|
|
121
|
-
|
|
122
104
|
private mapState(car: DataSchemes.Car): string {
|
|
123
105
|
const available = {
|
|
124
106
|
selector_condition_new: 'Neu',
|
|
@@ -3,7 +3,7 @@ import { DataSchemes } from '@bytebrand/car-schema';
|
|
|
3
3
|
|
|
4
4
|
import { de } from '@bytebrand/i18n-dictionaries';
|
|
5
5
|
import { Injectable } from '@nestjs/common';
|
|
6
|
-
import { ConfigService } from '../services
|
|
6
|
+
import { ConfigService } from '../services';
|
|
7
7
|
import { MeinstadtJsonItem } from '../interfaces';
|
|
8
8
|
|
|
9
9
|
@Injectable()
|
|
@@ -73,8 +73,7 @@ export class MeinstadtTransformer {
|
|
|
73
73
|
private getDescription(car: DataSchemes.Car): string {
|
|
74
74
|
const usageType = get(car, 'offer.offerDescription', null);
|
|
75
75
|
if (usageType) {
|
|
76
|
-
|
|
77
|
-
return afterFromatting;
|
|
76
|
+
return usageType.replace(/\\/g, ',').replace(/\\/g, ',').replace(/,,/g, ',');
|
|
78
77
|
} else return null;
|
|
79
78
|
}
|
|
80
79
|
}
|