Browse Source

feat(server): Create Populator class for populating initial data

Michael Bromley 7 years ago
parent
commit
3b06331874

+ 2 - 1
server/src/bootstrap.ts

@@ -23,7 +23,8 @@ export async function bootstrap(userConfig: Partial<VendureConfig>): Promise<INe
     // tslint:disable-next-line:whitespace
     const appModule = await import('./app.module');
     const app = await NestFactory.create(appModule.AppModule, { cors: config.cors });
-    return app.listen(config.port);
+    await app.listen(config.port);
+    return app;
 }
 
 /**

+ 3 - 2
server/src/data-import/data-import.module.ts

@@ -5,10 +5,11 @@ import { ServiceModule } from '../service/service.module';
 
 import { ImportParser } from './providers/import-parser/import-parser';
 import { Importer } from './providers/importer/importer';
+import { Populator } from './providers/populator/populator';
 
 @Module({
     imports: [ServiceModule, ConfigModule],
-    exports: [ImportParser, Importer],
-    providers: [ImportParser, Importer],
+    exports: [ImportParser, Importer, Populator],
+    providers: [ImportParser, Importer, Populator],
 })
 export class DataImportModule {}

+ 1 - 0
server/src/data-import/index.ts

@@ -0,0 +1 @@
+export * from './providers/populator/populator';

+ 98 - 0
server/src/data-import/providers/populator/populator.ts

@@ -0,0 +1,98 @@
+import { Injectable } from '@nestjs/common';
+
+import { LanguageCode } from '../../../../../shared/generated-types';
+import { RequestContext } from '../../../api/common/request-context';
+import { TaxCategory } from '../../../entity';
+import { Zone } from '../../../entity/zone/zone.entity';
+import { ChannelService } from '../../../service/services/channel.service';
+import { CountryService } from '../../../service/services/country.service';
+import { TaxCategoryService } from '../../../service/services/tax-category.service';
+import { TaxRateService } from '../../../service/services/tax-rate.service';
+import { ZoneService } from '../../../service/services/zone.service';
+
+export interface CountryData {
+    code: string;
+    name: string;
+    zone: string;
+}
+export interface InitialData {
+    defaultLanguage: LanguageCode;
+    countries: CountryData[];
+    taxRates: Array<{ name: string; percentage: number }>;
+}
+
+type ZoneMap = Map<string, { entity: Zone; members: string[] }>;
+
+@Injectable()
+export class Populator {
+    constructor(
+        private countryService: CountryService,
+        private zoneService: ZoneService,
+        private channelService: ChannelService,
+        private taxRateService: TaxRateService,
+        private taxCategoryService: TaxCategoryService,
+    ) {}
+
+    async populateInitialData(data: InitialData) {
+        const channel = await this.channelService.getDefaultChannel();
+        const ctx = new RequestContext({
+            isAuthorized: true,
+            authorizedAsOwnerOnly: false,
+            channel,
+            languageCode: data.defaultLanguage,
+        });
+
+        const zoneMap = await this.populateCountries(ctx, data.countries);
+        await this.populateTaxRates(ctx, data.taxRates, zoneMap);
+    }
+
+    private async populateCountries(ctx: RequestContext, countries: CountryData[]): Promise<ZoneMap> {
+        const zones: ZoneMap = new Map();
+        for (const { name, code, zone } of countries) {
+            const countryEntity = await this.countryService.create(ctx, {
+                code,
+                enabled: true,
+                translations: [{ languageCode: ctx.languageCode, name }],
+            });
+
+            let zoneItem = zones.get(zone);
+            if (!zoneItem) {
+                const zoneEntity = await this.zoneService.create(ctx, { name: zone });
+                zoneItem = { entity: zoneEntity, members: [] };
+                zones.set(zone, zoneItem);
+            }
+            zoneItem.members.push(countryEntity.id as string);
+        }
+
+        // add the countries to the respective zones
+        for (const zoneItem of zones.values()) {
+            await this.zoneService.addMembersToZone(ctx, {
+                zoneId: zoneItem.entity.id as string,
+                memberIds: zoneItem.members,
+            });
+        }
+        return zones;
+    }
+
+    private async populateTaxRates(
+        ctx: RequestContext,
+        taxRates: Array<{ name: string; percentage: number }>,
+        zoneMap: ZoneMap,
+    ) {
+        const taxCategories: TaxCategory[] = [];
+
+        for (const taxRate of taxRates) {
+            const category = await this.taxCategoryService.create({ name: taxRate.name });
+
+            for (const { entity } of zoneMap.values()) {
+                await this.taxRateService.create({
+                    zoneId: entity.id as string,
+                    value: taxRate.percentage,
+                    categoryId: category.id as string,
+                    name: `${taxRate.name} ${entity.name}`,
+                    enabled: true,
+                });
+            }
+        }
+    }
+}

+ 40 - 0
server/src/entity/index.ts

@@ -0,0 +1,40 @@
+export * from './address/address.entity';
+export * from './administrator/administrator.entity';
+export * from './asset/asset.entity';
+export * from './base/base.entity';
+export * from './channel/channel.entity';
+export * from './country/country.entity';
+export * from './country/country-translation.entity';
+export * from './customer/customer.entity';
+export * from './customer-group/customer-group.entity';
+export * from './facet/facet.entity';
+export * from './facet/facet-translation.entity';
+export * from './facet-value/facet-value.entity';
+export * from './facet-value/facet-value-translation.entity';
+export * from './order/order.entity';
+export * from './order-item/order-item.entity';
+export * from './order-line/order-line.entity';
+export * from './payment/payment.entity';
+export * from './payment-method/payment-method.entity';
+export * from './product/product.entity';
+export * from './product/product-translation.entity';
+export * from './product-category/product-category.entity';
+export * from './product-category/product-category-translation.entity';
+export * from './product-option/product-option.entity';
+export * from './product-option/product-option-translation.entity';
+export * from './product-option-group/product-option-group.entity';
+export * from './product-option-group/product-option-group-translation.entity';
+export * from './product-variant/product-variant.entity';
+export * from './product-variant/product-variant-translation.entity';
+export * from './product-variant/product-variant-price.entity';
+export * from './promotion/promotion.entity';
+export * from './role/role.entity';
+export * from './session/session.entity';
+export * from './session/anonymous-session.entity';
+export * from './session/authenticated-session.entity';
+export * from './shipping-item/shipping-item.entity';
+export * from './shipping-method/shipping-method.entity';
+export * from './tax-category/tax-category.entity';
+export * from './tax-rate/tax-rate.entity';
+export * from './user/user.entity';
+export * from './zone/zone.entity';

+ 2 - 0
server/src/index.ts

@@ -2,3 +2,5 @@ export { bootstrap } from './bootstrap';
 export * from './config/index';
 export * from './email/index';
 export * from './plugin/index';
+export * from './entity/index';
+export * from './data-import/index';