@bytebrand/export-cars 1.8.0 → 1.10.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 +4 -1
- package/dist/configs/alleskralle.config.js.map +1 -1
- package/dist/configs/as24.config.js +1 -0
- package/dist/configs/as24.config.js.map +1 -1
- package/dist/configs/auto24.config.js +1 -0
- package/dist/configs/auto24.config.js.map +1 -1
- package/dist/configs/autoboerse.config.js +2 -1
- package/dist/configs/autoboerse.config.js.map +1 -1
- package/dist/configs/autouncle.config.js +2 -1
- package/dist/configs/autouncle.config.js.map +1 -1
- package/dist/configs/by-owner.config.js +1 -0
- package/dist/configs/by-owner.config.js.map +1 -1
- package/dist/configs/config.d.ts +7 -1
- package/dist/configs/config.js +11 -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 +2 -1
- package/dist/configs/dasparking.config.js.map +1 -1
- package/dist/configs/eauto.config.js +2 -3
- package/dist/configs/eauto.config.js.map +1 -1
- package/dist/configs/facebook-shop.config.js +1 -0
- package/dist/configs/facebook-shop.config.js.map +1 -1
- package/dist/configs/fb.config.js +2 -1
- package/dist/configs/fb.config.js.map +1 -1
- package/dist/configs/google.config.js +2 -1
- package/dist/configs/google.config.js.map +1 -1
- package/dist/configs/kleinanzeigefocus.config.js +2 -2
- package/dist/configs/kleinanzeigefocus.config.js.map +1 -1
- package/dist/configs/marktde.config.js +2 -1
- package/dist/configs/marktde.config.js.map +1 -1
- package/dist/configs/meinstadt.config.js +1 -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/configs/yescar.config.js +1 -0
- package/dist/configs/yescar.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/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 +1 -0
- package/dist/enums/index.js +1 -0
- package/dist/enums/index.js.map +1 -1
- package/dist/export.command.d.ts +1 -1
- package/dist/export.command.js +2 -2
- package/dist/export.command.js.map +1 -1
- package/dist/exporters/auto24.exporter.js +1 -1
- package/dist/exporters/auto24.exporter.js.map +1 -1
- package/dist/exporters/autouncle.exporter.js +0 -1
- package/dist/exporters/autouncle.exporter.js.map +1 -1
- package/dist/exporters/meinstadt.exporter.js +0 -1
- package/dist/exporters/meinstadt.exporter.js.map +1 -1
- package/dist/exporters/ooyyo.exporter.js +1 -1
- package/dist/exporters/ooyyo.exporter.js.map +1 -1
- package/dist/interfaces/export-item.interface.d.ts +5 -0
- package/dist/interfaces/params.interface.d.ts +1 -6
- package/dist/services/{marketing-images.service.d.ts → images.service.d.ts} +9 -5
- package/dist/services/images.service.js +153 -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/as24.transformer.d.ts +1 -2
- package/dist/transformers/as24.transformer.js +3 -4
- package/dist/transformers/as24.transformer.js.map +1 -1
- package/dist/transformers/auto24.transfomer.d.ts +5 -6
- package/dist/transformers/auto24.transfomer.js +22 -26
- package/dist/transformers/auto24.transfomer.js.map +1 -1
- package/dist/transformers/autouncle.transformer.d.ts +5 -6
- package/dist/transformers/autouncle.transformer.js +9 -34
- package/dist/transformers/autouncle.transformer.js.map +1 -1
- package/dist/transformers/facebook-shop.transformer.d.ts +5 -4
- package/dist/transformers/facebook-shop.transformer.js +8 -11
- package/dist/transformers/facebook-shop.transformer.js.map +1 -1
- package/dist/transformers/fb.transformer.d.ts +2 -3
- package/dist/transformers/fb.transformer.js +12 -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/modix.transformer.js +1 -2
- 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 +5 -2
- package/src/configs/as24.config.ts +2 -1
- package/src/configs/auto24.config.ts +3 -2
- package/src/configs/autoboerse.config.ts +3 -3
- package/src/configs/autouncle.config.ts +3 -2
- package/src/configs/by-owner.config.ts +4 -3
- package/src/configs/config.ts +8 -2
- package/src/configs/criteo.config.ts +3 -2
- package/src/configs/dasparking.config.ts +3 -2
- package/src/configs/eauto.config.ts +3 -4
- package/src/configs/facebook-shop.config.ts +2 -1
- package/src/configs/fb.config.ts +3 -2
- package/src/configs/google.config.ts +3 -2
- package/src/configs/{kleinanzeigefocus.config.ts → kleinanzeigeFocus.config.ts} +3 -3
- package/src/configs/marktde.config.ts +4 -3
- package/src/configs/meinstadt.config.ts +3 -2
- package/src/configs/ooyyo.config.ts +2 -1
- package/src/configs/yescar.config.ts +2 -1
- package/src/constants/modix/index.ts +1 -0
- package/src/enums/file-types.enum.ts +1 -1
- package/src/enums/image-type.enum.ts +4 -0
- package/src/enums/index.ts +1 -0
- package/src/export.command.ts +1 -1
- package/src/exporters/auto24.exporter.ts +2 -4
- package/src/exporters/autouncle.exporter.ts +7 -5
- package/src/exporters/meinstadt.exporter.ts +6 -4
- package/src/exporters/ooyyo.exporter.ts +3 -4
- package/src/interfaces/export-item.interface.ts +5 -0
- package/src/interfaces/params.interface.ts +1 -6
- package/src/services/images.service.ts +162 -0
- package/src/services/index.ts +1 -2
- package/src/transformers/as24.transformer.ts +2 -3
- package/src/transformers/auto24.transfomer.ts +20 -29
- package/src/transformers/autouncle.transformer.ts +11 -39
- package/src/transformers/facebook-shop.transformer.ts +7 -13
- package/src/transformers/fb.transformer.ts +24 -44
- package/src/transformers/google.transformer.ts +11 -28
- package/src/transformers/modix.transformer.ts +5 -3
- package/src/transformers/ooyyo.transformer.ts +4 -18
- package/src/transformers/rubrikk.transformer.ts +5 -16
- package/d.json +0 -1
- 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,162 @@
|
|
|
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
|
+
'https://images.auto.de/carimage/noimage/7pNvWELuWhZX/large-cached.jpeg',
|
|
100
|
+
'https://images.auto.de/carimage/noimage/GvyXmrpaf1D6/large-cached.jpeg',
|
|
101
|
+
'https://images.auto.de/carimage/noimage/gY1zF8PXzH2W/large-cached.jpeg',
|
|
102
|
+
'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 responseData = configs.find(config => config.channelCode.includes(this.configService.config.exportType));
|
|
127
|
+
let id;
|
|
128
|
+
!responseData?.id ? (id = this.configService.config.marketingImageId) : (id = responseData.id);
|
|
129
|
+
return this.userService.getMarketingImageConfig(id);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
private transformImagesArrayIntoObject(images: { [imageCode: string]: string }[]) {
|
|
133
|
+
const result: { [imageCode: string]: string } = {};
|
|
134
|
+
images.forEach(image => {
|
|
135
|
+
const imageCode = image.imageCodePredicted.split('-')[0];
|
|
136
|
+
result[imageCode] = image.imageIdentifier;
|
|
137
|
+
});
|
|
138
|
+
return result;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
private transform(config: MarketingImageConfigInterface): { marketingImageCodes: string[] }[] {
|
|
142
|
+
return config.marketingImages.map(marketingImage => {
|
|
143
|
+
return {
|
|
144
|
+
marketingImageCodes: marketingImage.imageCodes,
|
|
145
|
+
};
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
protected getChannelPath(imageUrl: string, carId: string): string {
|
|
150
|
+
return `${imageUrl}/${[carId[0], carId[1], carId[2], carId].join('/')}`;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
protected getImagePathWithExtenstion(
|
|
154
|
+
imageUrl: string,
|
|
155
|
+
carId: string,
|
|
156
|
+
imageId: string,
|
|
157
|
+
config: MarketingImageConfigsInterface,
|
|
158
|
+
): string {
|
|
159
|
+
const { channelCode, imageExtension } = config;
|
|
160
|
+
return `${this.getChannelPath(imageUrl, carId)}/${channelCode.replace(/ /g, '-')}-${imageId}.${imageExtension}`;
|
|
161
|
+
}
|
|
162
|
+
}
|
package/src/services/index.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { get, isEmpty, isNil, set, toNumber, toSafeInteger, upperFirst } from 'lodash';
|
|
2
2
|
import { DataSchemes } from '@bytebrand/car-schema';
|
|
3
3
|
import { CarDescriptionFactory, DescriptionTypeEnum } from '@bytebrand/car-description';
|
|
4
|
-
import { MappingService } from '../services
|
|
4
|
+
import { MappingService, UserService } from '../services';
|
|
5
5
|
import { MappingRules } from '../interfaces/mapping-rules.interface';
|
|
6
6
|
import { Injectable } from '@nestjs/common';
|
|
7
7
|
import { LoggerService } from '@bytebrand/cronicle-helper';
|
|
8
|
-
import { UserService } from '../services';
|
|
9
8
|
|
|
10
9
|
@Injectable()
|
|
11
10
|
export class As24Transformer {
|
|
@@ -114,7 +113,7 @@ export class As24Transformer {
|
|
|
114
113
|
|
|
115
114
|
protected numberToNumber(field: number): number {
|
|
116
115
|
const result = isNil(field) ? null : toNumber(field);
|
|
117
|
-
return
|
|
116
|
+
return result < 0 || isNaN(result) ? undefined : result;
|
|
118
117
|
}
|
|
119
118
|
|
|
120
119
|
protected numberToInteger(field: number): number {
|
|
@@ -1,25 +1,25 @@
|
|
|
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
11
|
|
|
12
12
|
@Injectable()
|
|
13
13
|
export class Auto24Transformer {
|
|
14
14
|
private translator: Translator;
|
|
15
15
|
|
|
16
|
-
constructor(private configService: ConfigService) {
|
|
16
|
+
constructor(private configService: ConfigService, private readonly imageService: ImagesService) {
|
|
17
17
|
this.translator = new Translator(de);
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
transform(car: DataSchemes.Car, imboImages: ImboImageResponseInterface[]): Auto24XmlItem {
|
|
20
|
+
async transform(car: DataSchemes.Car, imboImages: ImboImageResponseInterface[]): Promise<Auto24XmlItem> {
|
|
21
21
|
const carId = toString(get(car, '_id', ''));
|
|
22
|
-
|
|
22
|
+
const transformedImages = await this.imageService.getImages(car, imboImages, this.configService.config.imageType);
|
|
23
23
|
let userlink = `https://www.${this.configService.config.domain}/search/vehicle/${carId}`;
|
|
24
24
|
if (this.configService.config.campaign) {
|
|
25
25
|
userlink += `?source=classifieds&medium=listing&campaign=${this.configService.config.campaign}`;
|
|
@@ -37,9 +37,9 @@ export class Auto24Transformer {
|
|
|
37
37
|
consumptionK: toString(get(car, 'consumption.consumptionCombined', '')),
|
|
38
38
|
co2: toString(get(car, 'environmentEmissions.co2', '')),
|
|
39
39
|
efficiencyclass: this.translateSelector(get(car, 'environmentEmissions.energyEfficiencyClass', '')),
|
|
40
|
-
image:
|
|
40
|
+
image: transformedImages[0],
|
|
41
41
|
registration: this.getRegistrationField(get(car, 'mainData.firstRegistration') as number),
|
|
42
|
-
images:
|
|
42
|
+
images: transformedImages,
|
|
43
43
|
price: toString(get(car, 'price.currentSalesPrice', '')),
|
|
44
44
|
power: toString(get(car, 'engineData.powerKW', '')),
|
|
45
45
|
zip: toString(get(car, 'location.zipCode', '')),
|
|
@@ -48,6 +48,11 @@ export class Auto24Transformer {
|
|
|
48
48
|
companyname: 'www.auto.de',
|
|
49
49
|
extras: this.getExtrasField(car),
|
|
50
50
|
sellertype: 'dealer',
|
|
51
|
+
condition: this.getCondition(car),
|
|
52
|
+
dealer_homepage_url: 'https://www.auto.de',
|
|
53
|
+
dealer_email: ' auto@auto.de',
|
|
54
|
+
dealer_name: ' Auto.de',
|
|
55
|
+
dealer_phone: '+498004030182',
|
|
51
56
|
};
|
|
52
57
|
}
|
|
53
58
|
|
|
@@ -133,27 +138,13 @@ export class Auto24Transformer {
|
|
|
133
138
|
.join(', ');
|
|
134
139
|
}
|
|
135
140
|
|
|
136
|
-
private
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
}
|
|
142
|
-
|
|
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`;
|
|
141
|
+
private getCondition(car: DataSchemes.Car): string {
|
|
142
|
+
const available = {
|
|
143
|
+
selector_condition_new: 'Neu',
|
|
144
|
+
selector_condition_used: 'Gebraucht',
|
|
145
|
+
selector_unknown: 'Gebraucht',
|
|
146
|
+
};
|
|
147
|
+
const condition = get(car, 'mainData.condition', 'selector_unknown');
|
|
148
|
+
return get(available, condition);
|
|
158
149
|
}
|
|
159
150
|
}
|
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
import { TranslatorExtended } from '@bytebrand/schema-tools';
|
|
2
2
|
import { de, deVehicleDetailsPage, deVehicleProps } from '@bytebrand/i18n-dictionaries';
|
|
3
|
-
import {
|
|
3
|
+
import {get, toString, isEmpty, toSafeInteger } from 'lodash';
|
|
4
4
|
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
|
-
|
|
8
|
+
|
|
9
|
+
import { ConfigService, ImagesService } from '../services';
|
|
9
10
|
import { Injectable } from '@nestjs/common';
|
|
10
11
|
import { DEFAULT_ADDR1, DEFAULT_CITY, DEFAULT_ZIP, MIN_MILEAGES } from '../constants/autouncle.contants';
|
|
11
12
|
import { AutouncleJsonItem } from '../interfaces';
|
|
12
|
-
import {
|
|
13
|
+
import { ImboImageResponseInterface } from '@bytebrand/chunkable';
|
|
13
14
|
|
|
14
15
|
@Injectable()
|
|
15
16
|
export class AutouncleTransformer {
|
|
16
17
|
private translator: TranslatorExtended;
|
|
17
18
|
private postalCodesService: DePostalCodesService;
|
|
18
19
|
|
|
19
|
-
constructor(private configService: ConfigService) {
|
|
20
|
+
constructor(private configService: ConfigService, private imageService: ImagesService) {
|
|
20
21
|
const dict = { ...de, ...deVehicleProps, ...deVehicleDetailsPage };
|
|
21
22
|
this.translator = new TranslatorExtended(dict);
|
|
22
23
|
this.postalCodesService = DePostalCodesService.getInstance();
|
|
@@ -28,13 +29,16 @@ export class AutouncleTransformer {
|
|
|
28
29
|
owner,
|
|
29
30
|
}: {
|
|
30
31
|
car: DataSchemes.Car;
|
|
31
|
-
images:
|
|
32
|
+
images: ImboImageResponseInterface[];
|
|
32
33
|
metadata?: unknown;
|
|
33
34
|
owner: unknown;
|
|
34
35
|
}): Promise<AutouncleJsonItem> {
|
|
35
36
|
const autodeId = toString(get(car, '_id', ''));
|
|
36
37
|
const address = await this.getAddress(car, owner);
|
|
37
|
-
|
|
38
|
+
const image_urls = await this.imageService.getImages(car, images, this.configService.config.imageType);
|
|
39
|
+
const transformed_images = image_urls.map(url => {
|
|
40
|
+
return { url };
|
|
41
|
+
});
|
|
38
42
|
return {
|
|
39
43
|
back_link: `https://www.${this.configService.config.domain}/search/vehicle/${autodeId}?source=classifieds&medium=cpc&campaign=autouncle`,
|
|
40
44
|
make: toString(get(car, 'mainData.make', '')),
|
|
@@ -61,7 +65,7 @@ export class AutouncleTransformer {
|
|
|
61
65
|
seller_name: 'auto.de',
|
|
62
66
|
seller_id: toString(get(car, 'metaData.ownerId', '')),
|
|
63
67
|
description: toString(get(car, 'offer.offerDescription', '')),
|
|
64
|
-
images:
|
|
68
|
+
images: transformed_images,
|
|
65
69
|
fuel_economy: toString(get(car, 'consumption.consumptionCombined', '')),
|
|
66
70
|
co2_emission: toString(get(car, 'environmentEmissions.co2', '')),
|
|
67
71
|
co2_effiency_class: toString(get(car, 'environmentEmissions.energyEfficiencyClass', '')),
|
|
@@ -229,36 +233,4 @@ export class AutouncleTransformer {
|
|
|
229
233
|
private has4WD(): string {
|
|
230
234
|
return '';
|
|
231
235
|
}
|
|
232
|
-
|
|
233
|
-
private getImagesField(carId: string, mainImageId: string, images: unknown[]): { url: string }[] {
|
|
234
|
-
const defImages = [
|
|
235
|
-
{ url: 'https://images.auto.de/carimage/noimage/7pNvWELuWhZX/large-cached.jpeg' },
|
|
236
|
-
{ url: 'https://images.auto.de/carimage/noimage/GvyXmrpaf1D6/large-cached.jpeg' },
|
|
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
|
-
};
|
|
263
|
-
}
|
|
264
236
|
}
|
|
@@ -7,7 +7,7 @@ import { TranslatorExtended } from '@bytebrand/schema-tools';
|
|
|
7
7
|
import { DataSchemes } from '@bytebrand/car-schema';
|
|
8
8
|
|
|
9
9
|
import { FacebookShopItem } from '../interfaces';
|
|
10
|
-
import { ConfigService } from '../services';
|
|
10
|
+
import { ConfigService, ImagesService } from '../services';
|
|
11
11
|
import { Description } from '../interfaces/description.interface';
|
|
12
12
|
import { FbDescription } from './fb-description.transformer';
|
|
13
13
|
import { FbEquipment } from './fb-equipment.transformer';
|
|
@@ -16,12 +16,14 @@ import { FbEquipment } from './fb-equipment.transformer';
|
|
|
16
16
|
export class FacebookShopTransformer {
|
|
17
17
|
private translator: TranslatorExtended;
|
|
18
18
|
|
|
19
|
-
constructor(private readonly configService: ConfigService) {
|
|
19
|
+
constructor(private readonly configService: ConfigService, private readonly imageService: ImagesService) {
|
|
20
20
|
const dict = { ...de, ...deVehicleProps, ...deVehicleDetailsPage };
|
|
21
21
|
this.translator = new TranslatorExtended(dict);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
async transform({ car }: { car: DataSchemes.Car }): Promise<FacebookShopItem> {
|
|
24
|
+
async transform({ car, images }: { car: DataSchemes.Car; images: any }): Promise<FacebookShopItem> {
|
|
25
|
+
const imageLinks = await this.imageService.getImages(car, images, this.configService.config.imageType);
|
|
26
|
+
|
|
25
27
|
return {
|
|
26
28
|
id: { value: get(car, 'metaData.vehicleId'), isGoogle: true },
|
|
27
29
|
title: { value: this.getTitle(car), isGoogle: true },
|
|
@@ -30,9 +32,9 @@ export class FacebookShopTransformer {
|
|
|
30
32
|
condition: { value: this.getCondition(car), isGoogle: true },
|
|
31
33
|
price: { value: this.getPrice(car), isGoogle: true },
|
|
32
34
|
link: { value: this.getCarLink(car), isGoogle: true },
|
|
33
|
-
image_link: { value:
|
|
35
|
+
image_link: { value: imageLinks[0], isGoogle: true },
|
|
34
36
|
brand: { value: get(car, 'mainData.make', ''), isGoogle: true },
|
|
35
|
-
additional_image_link: { value:
|
|
37
|
+
additional_image_link: { value: imageLinks[0], isGoogle: false },
|
|
36
38
|
quantity_to_sell_on_facebook: { value: 1, isGoogle: true },
|
|
37
39
|
google_product_category: { value: '916', isGoogle: true },
|
|
38
40
|
sale_price: { value: this.getPrice(car), isGoogle: true },
|
|
@@ -83,12 +85,4 @@ export class FacebookShopTransformer {
|
|
|
83
85
|
private getDescription(car: DataSchemes.Car): Description[] {
|
|
84
86
|
return FbDescription.create(car, this.translator, new FbEquipment()).getDescriptionArray();
|
|
85
87
|
}
|
|
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
88
|
}
|
|
@@ -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();
|
|
@@ -67,6 +63,10 @@ export class FbTransformer {
|
|
|
67
63
|
const year = this.getYear(car);
|
|
68
64
|
const dealerInfo = this.getDealerItems(car);
|
|
69
65
|
const address = await this.getAddress(car, owner);
|
|
66
|
+
const image_links = await this.imagesService.getImages(car, images, ImageType.marketing);
|
|
67
|
+
const transformedImages = image_links.map(el => {
|
|
68
|
+
return { url: el };
|
|
69
|
+
});
|
|
70
70
|
|
|
71
71
|
return {
|
|
72
72
|
fb_page_id: '176306386132',
|
|
@@ -81,7 +81,7 @@ export class FbTransformer {
|
|
|
81
81
|
make: toString(get(car, 'mainData.make', '')),
|
|
82
82
|
model: toString(get(car, 'mainData.model', '')),
|
|
83
83
|
trim: this.getTrim(car),
|
|
84
|
-
image:
|
|
84
|
+
image: transformedImages,
|
|
85
85
|
year: toString(year),
|
|
86
86
|
mileage: {
|
|
87
87
|
value: this.getMileage(car),
|
|
@@ -152,15 +152,13 @@ export class FbTransformer {
|
|
|
152
152
|
dealer_email: string;
|
|
153
153
|
dealer_phone: string;
|
|
154
154
|
} {
|
|
155
|
-
|
|
155
|
+
return {
|
|
156
156
|
dealer_communication_channel: 'LEAD_FORM',
|
|
157
157
|
dealer_id: get(car, 'metaData.ownerId'),
|
|
158
158
|
dealer_privacy_policy_url: 'https://www.auto.de/einwilligungserklaerung-datenschutz-agb/',
|
|
159
159
|
dealer_email: 'auto@auto.de',
|
|
160
160
|
dealer_phone: '+498000008300',
|
|
161
161
|
};
|
|
162
|
-
|
|
163
|
-
return items;
|
|
164
162
|
}
|
|
165
163
|
|
|
166
164
|
private getTitle(car: DataSchemes.Car): string {
|
|
@@ -288,14 +286,17 @@ export class FbTransformer {
|
|
|
288
286
|
},
|
|
289
287
|
};
|
|
290
288
|
}
|
|
289
|
+
|
|
291
290
|
private isEmptyLocation(location: DePostalCodesEntryInterface): boolean {
|
|
292
291
|
if (!location) return true;
|
|
293
292
|
return !location['Place Name'] || !(location.Latitude && location.Longitude);
|
|
294
293
|
}
|
|
294
|
+
|
|
295
295
|
private isEmptyAddress(address: unknown): boolean {
|
|
296
296
|
if (!address) return true;
|
|
297
297
|
return ['city', 'zip', 'country'].every((key: string) => isEmpty(address[key]));
|
|
298
298
|
}
|
|
299
|
+
|
|
299
300
|
private async getCoords(
|
|
300
301
|
car: DataSchemes.Car,
|
|
301
302
|
locationEntry: DePostalCodesEntryInterface,
|
|
@@ -331,6 +332,7 @@ export class FbTransformer {
|
|
|
331
332
|
}
|
|
332
333
|
return this.translator.translateVal(colorSelection);
|
|
333
334
|
}
|
|
335
|
+
|
|
334
336
|
private getInteriorColor(car: DataSchemes.Car): string {
|
|
335
337
|
let colorSelection = get(car, 'interior.interiorColor', 'other');
|
|
336
338
|
if (!colorSelection || colorSelection === 'selector_unknown') {
|
|
@@ -372,28 +374,6 @@ export class FbTransformer {
|
|
|
372
374
|
return mileage <= FB_MIN_MILEAGES ? FB_MIN_MILEAGES + 1 : mileage;
|
|
373
375
|
}
|
|
374
376
|
|
|
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
377
|
private getHighlights(car: DataSchemes.Car): { type: unknown; value: unknown }[] {
|
|
398
378
|
const facebookFeatures = [
|
|
399
379
|
{ key: 'assistants.abs', type: 'abs_brakes', value: 'ABS' },
|
|
@@ -1,25 +1,29 @@
|
|
|
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
|
|
26
|
+
const transformedImages = await this.imageService.getImages(car, images, this.configService.config.imageType);
|
|
23
27
|
|
|
24
28
|
return {
|
|
25
29
|
id: carId,
|
|
@@ -28,7 +32,7 @@ export class GoogleTransformer {
|
|
|
28
32
|
google_product_category: this.getBreadcrumbs(car),
|
|
29
33
|
product_type: this.getCategory(car),
|
|
30
34
|
link: this.getLink(car),
|
|
31
|
-
image_link:
|
|
35
|
+
image_link: transformedImages[0],
|
|
32
36
|
condition: this.mapState(car),
|
|
33
37
|
availability: this.getAvailability(car),
|
|
34
38
|
brand: get(car, 'mainData.make', ''),
|
|
@@ -98,27 +102,6 @@ export class GoogleTransformer {
|
|
|
98
102
|
return this.translator.translateVal(colorSelection);
|
|
99
103
|
}
|
|
100
104
|
|
|
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
105
|
private mapState(car: DataSchemes.Car): string {
|
|
123
106
|
const available = {
|
|
124
107
|
selector_condition_new: 'Neu',
|