@vendure/core
Version:
A modern, headless ecommerce framework
318 lines • 14.6 kB
JavaScript
;
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Populator = void 0;
const common_1 = require("@nestjs/common");
const normalize_string_1 = require("@vendure/common/lib/normalize-string");
const shared_utils_1 = require("@vendure/common/lib/shared-utils");
const request_context_1 = require("../../../api/common/request-context");
const config_1 = require("../../../config");
const manual_fulfillment_handler_1 = require("../../../config/fulfillment/manual-fulfillment-handler");
const transactional_connection_1 = require("../../../connection/transactional-connection");
const entity_1 = require("../../../entity");
const service_1 = require("../../../service");
const channel_service_1 = require("../../../service/services/channel.service");
const country_service_1 = require("../../../service/services/country.service");
const search_service_1 = require("../../../service/services/search.service");
const tax_category_service_1 = require("../../../service/services/tax-category.service");
const tax_rate_service_1 = require("../../../service/services/tax-rate.service");
const zone_service_1 = require("../../../service/services/zone.service");
const asset_importer_1 = require("../asset-importer/asset-importer");
/**
* @description
* Responsible for populating the database with {@link InitialData}, i.e. non-product data such as countries, tax rates,
* shipping methods, payment methods & roles.
*
* @docsCategory import-export
*/
let Populator = class Populator {
/** @internal */
constructor(countryService, zoneService, channelService, taxRateService, taxCategoryService, shippingMethodService, paymentMethodService, collectionService, facetValueService, searchService, assetImporter, roleService, configService, connection, requestContextService) {
this.countryService = countryService;
this.zoneService = zoneService;
this.channelService = channelService;
this.taxRateService = taxRateService;
this.taxCategoryService = taxCategoryService;
this.shippingMethodService = shippingMethodService;
this.paymentMethodService = paymentMethodService;
this.collectionService = collectionService;
this.facetValueService = facetValueService;
this.searchService = searchService;
this.assetImporter = assetImporter;
this.roleService = roleService;
this.configService = configService;
this.connection = connection;
this.requestContextService = requestContextService;
}
/**
* @description
* Should be run *before* populating the products, so that there are TaxRates by which
* product prices can be set. If the `channel` argument is set, then any {@link ChannelAware}
* entities will be assigned to that Channel.
*/
async populateInitialData(data, channel) {
const ctx = await this.createRequestContext(data, channel);
let zoneMap;
try {
zoneMap = await this.populateCountries(ctx, data.countries);
}
catch (e) {
config_1.Logger.error('Could not populate countries');
config_1.Logger.error(e, 'populator', e.stack);
throw e;
}
try {
await this.populateTaxRates(ctx, data.taxRates, zoneMap);
}
catch (e) {
config_1.Logger.error('Could not populate tax rates');
config_1.Logger.error(e, 'populator', e.stack);
}
try {
await this.populateShippingMethods(ctx, data.shippingMethods);
}
catch (e) {
config_1.Logger.error('Could not populate shipping methods');
config_1.Logger.error(e, 'populator', e.stack);
}
try {
await this.populatePaymentMethods(ctx, data.paymentMethods);
}
catch (e) {
config_1.Logger.error('Could not populate payment methods');
config_1.Logger.error(e, 'populator', e.stack);
}
try {
await this.setChannelDefaults(zoneMap, data, ctx.channel);
}
catch (e) {
config_1.Logger.error('Could not set channel defaults');
config_1.Logger.error(e, 'populator', e.stack);
}
try {
await this.populateRoles(ctx, data.roles);
}
catch (e) {
config_1.Logger.error('Could not populate roles');
config_1.Logger.error(e, 'populator', e.stack);
}
}
/**
* @description
* Should be run *after* the products have been populated, otherwise the expected FacetValues will not
* yet exist.
*/
async populateCollections(data, channel) {
var _a, _b;
const ctx = await this.createRequestContext(data, channel);
const allFacetValues = await this.facetValueService.findAll(ctx, ctx.languageCode);
const collectionMap = new Map();
for (const collectionDef of data.collections) {
const parent = collectionDef.parentName && collectionMap.get(collectionDef.parentName);
const parentId = parent ? parent.id.toString() : undefined;
const { assets } = await this.assetImporter.getAssets(collectionDef.assetPaths || [], ctx);
let filters = [];
try {
filters = (collectionDef.filters || []).map(filter => this.processFilterDefinition(filter, allFacetValues));
}
catch (e) {
config_1.Logger.error(e.message);
}
const collection = await this.collectionService.create(ctx, {
translations: [
{
languageCode: ctx.languageCode,
name: collectionDef.name,
description: collectionDef.description || '',
slug: (_a = collectionDef.slug) !== null && _a !== void 0 ? _a : collectionDef.name,
},
],
isPrivate: collectionDef.private || false,
parentId,
assetIds: assets.map(a => a.id.toString()),
featuredAssetId: assets.length ? assets[0].id.toString() : undefined,
filters,
inheritFilters: (_b = collectionDef.inheritFilters) !== null && _b !== void 0 ? _b : true,
});
collectionMap.set(collectionDef.name, collection);
}
// Wait for the created collection operations to complete before running
// the reindex of the search index.
await new Promise(resolve => setTimeout(resolve, 50));
await this.searchService.reindex(ctx);
}
processFilterDefinition(filter, allFacetValues) {
switch (filter.code) {
case 'facet-value-filter':
const facetValueIds = filter.args.facetValueNames
.map(name => allFacetValues.find(fv => {
let facetName;
let valueName = name;
if (name.includes(':')) {
[facetName, valueName] = name.split(':');
return ((fv.name === valueName || fv.code === valueName) &&
(fv.facet.name === facetName || fv.facet.code === facetName));
}
else {
return fv.name === valueName || fv.code === valueName;
}
}))
.filter(shared_utils_1.notNullOrUndefined)
.map(fv => fv.id);
return {
code: filter.code,
arguments: [
{
name: 'facetValueIds',
value: JSON.stringify(facetValueIds),
},
{
name: 'containsAny',
value: filter.args.containsAny.toString(),
},
],
};
default:
throw new Error(`Filter with code "${filter.code}" is not recognized.`);
}
}
async createRequestContext(data, channel) {
const { superadminCredentials } = this.configService.authOptions;
const superAdminUser = await this.connection.rawConnection.getRepository(entity_1.User).findOne({
where: {
identifier: superadminCredentials.identifier,
},
});
const ctx = await this.requestContextService.create({
user: superAdminUser !== null && superAdminUser !== void 0 ? superAdminUser : undefined,
apiType: 'admin',
languageCode: data.defaultLanguage,
channelOrToken: channel !== null && channel !== void 0 ? channel : (await this.channelService.getDefaultChannel()),
});
return ctx;
}
async setChannelDefaults(zoneMap, data, channel) {
const defaultZone = zoneMap.get(data.defaultZone);
if (!defaultZone) {
throw new Error(`The defaultZone (${data.defaultZone}) did not match any existing or created zone names`);
}
const defaultZoneId = defaultZone.entity.id;
await this.channelService.update(request_context_1.RequestContext.empty(), {
id: channel.id,
defaultTaxZoneId: defaultZoneId,
defaultShippingZoneId: defaultZoneId,
});
}
async populateCountries(ctx, countries) {
const zoneMap = new Map();
const existingZones = await this.zoneService.getAllWithMembers(ctx);
for (const zone of existingZones) {
zoneMap.set(zone.name, { entity: zone, members: zone.members.map(m => m.id) });
}
for (const { name, code, zone } of countries) {
const countryEntity = await this.countryService.create(ctx, {
code,
enabled: true,
translations: [{ languageCode: ctx.languageCode, name }],
});
let zoneItem = zoneMap.get(zone);
if (!zoneItem) {
const zoneEntity = await this.zoneService.create(ctx, { name: zone });
zoneItem = { entity: zoneEntity, members: [] };
zoneMap.set(zone, zoneItem);
}
if (!zoneItem.members.includes(countryEntity.id)) {
zoneItem.members.push(countryEntity.id);
}
}
// add the countries to the respective zones
for (const zoneItem of zoneMap.values()) {
await this.zoneService.addMembersToZone(ctx, {
zoneId: zoneItem.entity.id,
memberIds: zoneItem.members,
});
}
return zoneMap;
}
async populateTaxRates(ctx, taxRates, zoneMap) {
for (const taxRate of taxRates) {
const category = await this.taxCategoryService.create(ctx, { name: taxRate.name });
for (const { entity } of zoneMap.values()) {
await this.taxRateService.create(ctx, {
zoneId: entity.id,
value: taxRate.percentage,
categoryId: category.id,
name: `${taxRate.name} ${entity.name}`,
enabled: true,
});
}
}
}
async populateShippingMethods(ctx, shippingMethods) {
for (const method of shippingMethods) {
await this.shippingMethodService.create(ctx, {
fulfillmentHandler: manual_fulfillment_handler_1.manualFulfillmentHandler.code,
checker: {
code: config_1.defaultShippingEligibilityChecker.code,
arguments: [{ name: 'orderMinimum', value: '0' }],
},
calculator: {
code: config_1.defaultShippingCalculator.code,
arguments: [
{ name: 'rate', value: method.price.toString() },
{ name: 'taxRate', value: method.taxRate ? method.taxRate.toString() : '0' },
{ name: 'includesTax', value: 'auto' },
],
},
code: (0, normalize_string_1.normalizeString)(method.name, '-'),
translations: [{ languageCode: ctx.languageCode, name: method.name, description: '' }],
});
}
}
async populatePaymentMethods(ctx, paymentMethods) {
for (const method of paymentMethods) {
await this.paymentMethodService.create(ctx, {
code: (0, normalize_string_1.normalizeString)(method.name, '-'),
enabled: true,
handler: method.handler,
translations: [{ languageCode: ctx.languageCode, name: method.name, description: '' }],
});
}
}
async populateRoles(ctx, roles) {
if (!roles) {
return;
}
for (const roleDef of roles) {
await this.roleService.create(ctx, roleDef);
}
}
};
exports.Populator = Populator;
exports.Populator = Populator = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [country_service_1.CountryService,
zone_service_1.ZoneService,
channel_service_1.ChannelService,
tax_rate_service_1.TaxRateService,
tax_category_service_1.TaxCategoryService,
service_1.ShippingMethodService,
service_1.PaymentMethodService,
service_1.CollectionService,
service_1.FacetValueService,
search_service_1.SearchService,
asset_importer_1.AssetImporter,
service_1.RoleService,
config_1.ConfigService,
transactional_connection_1.TransactionalConnection,
service_1.RequestContextService])
], Populator);
//# sourceMappingURL=populator.js.map