|
|
@@ -34,6 +34,7 @@ import { PromotionAction } from '../../config/promotion/promotion-action';
|
|
|
import { PromotionCondition } from '../../config/promotion/promotion-condition';
|
|
|
import { TransactionalConnection } from '../../connection/transactional-connection';
|
|
|
import { Order } from '../../entity/order/order.entity';
|
|
|
+import { PromotionTranslation } from '../../entity/promotion/promotion-translation.entity';
|
|
|
import { Promotion } from '../../entity/promotion/promotion.entity';
|
|
|
import { EventBus } from '../../event-bus';
|
|
|
import { PromotionEvent } from '../../event-bus/events/promotion-event';
|
|
|
@@ -41,6 +42,8 @@ import { ConfigArgService } from '../helpers/config-arg/config-arg.service';
|
|
|
import { CustomFieldRelationService } from '../helpers/custom-field-relation/custom-field-relation.service';
|
|
|
import { ListQueryBuilder } from '../helpers/list-query-builder/list-query-builder';
|
|
|
import { OrderState } from '../helpers/order-state-machine/order-state';
|
|
|
+import { TranslatableSaver } from '../helpers/translatable-saver/translatable-saver';
|
|
|
+import { TranslatorService } from '../helpers/translator/translator.service';
|
|
|
import { patchEntity } from '../helpers/utils/patch-entity';
|
|
|
|
|
|
import { ChannelService } from './channel.service';
|
|
|
@@ -64,6 +67,8 @@ export class PromotionService {
|
|
|
private configArgService: ConfigArgService,
|
|
|
private customFieldRelationService: CustomFieldRelationService,
|
|
|
private eventBus: EventBus,
|
|
|
+ private translatableSaver: TranslatableSaver,
|
|
|
+ private translator: TranslatorService,
|
|
|
) {
|
|
|
this.availableConditions = this.configService.promotionOptions.promotionConditions || [];
|
|
|
this.availableActions = this.configService.promotionOptions.promotionActions || [];
|
|
|
@@ -82,10 +87,13 @@ export class PromotionService {
|
|
|
ctx,
|
|
|
})
|
|
|
.getManyAndCount()
|
|
|
- .then(([items, totalItems]) => ({
|
|
|
- items,
|
|
|
- totalItems,
|
|
|
- }));
|
|
|
+ .then(([promotions, totalItems]) => {
|
|
|
+ const items = promotions.map(promotion => this.translator.translate(promotion, ctx));
|
|
|
+ return {
|
|
|
+ items,
|
|
|
+ totalItems,
|
|
|
+ };
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
async findOne(
|
|
|
@@ -93,10 +101,12 @@ export class PromotionService {
|
|
|
adjustmentSourceId: ID,
|
|
|
relations: RelationPaths<Promotion> = [],
|
|
|
): Promise<Promotion | undefined> {
|
|
|
- return this.connection.findOneInChannel(ctx, Promotion, adjustmentSourceId, ctx.channelId, {
|
|
|
- where: { deletedAt: null },
|
|
|
- relations,
|
|
|
- });
|
|
|
+ return this.connection
|
|
|
+ .findOneInChannel(ctx, Promotion, adjustmentSourceId, ctx.channelId, {
|
|
|
+ where: { deletedAt: null },
|
|
|
+ relations,
|
|
|
+ })
|
|
|
+ .then(promotion => promotion && this.translator.translate(promotion, ctx));
|
|
|
}
|
|
|
|
|
|
getPromotionConditions(ctx: RequestContext): ConfigurableOperationDefinition[] {
|
|
|
@@ -116,22 +126,21 @@ export class PromotionService {
|
|
|
);
|
|
|
const actions = input.actions.map(a => this.configArgService.parseInput('PromotionAction', a));
|
|
|
this.validateRequiredConditions(conditions, actions);
|
|
|
- const promotion = new Promotion({
|
|
|
- name: input.name,
|
|
|
- enabled: input.enabled,
|
|
|
- couponCode: input.couponCode,
|
|
|
- perCustomerUsageLimit: input.perCustomerUsageLimit,
|
|
|
- startsAt: input.startsAt,
|
|
|
- endsAt: input.endsAt,
|
|
|
- conditions,
|
|
|
- actions,
|
|
|
- priorityScore: this.calculatePriorityScore(input),
|
|
|
- });
|
|
|
- if (promotion.conditions.length === 0 && !promotion.couponCode) {
|
|
|
+ if (conditions.length === 0 && !input.couponCode) {
|
|
|
return new MissingConditionsError();
|
|
|
}
|
|
|
- await this.channelService.assignToCurrentChannel(promotion, ctx);
|
|
|
- const newPromotion = await this.connection.getRepository(ctx, Promotion).save(promotion);
|
|
|
+ const newPromotion = await this.translatableSaver.create({
|
|
|
+ ctx,
|
|
|
+ input,
|
|
|
+ entityType: Promotion,
|
|
|
+ translationType: PromotionTranslation,
|
|
|
+ beforeSave: async p => {
|
|
|
+ p.priorityScore = this.calculatePriorityScore(input);
|
|
|
+ p.conditions = conditions;
|
|
|
+ p.actions = actions;
|
|
|
+ await this.channelService.assignToCurrentChannel(p, ctx);
|
|
|
+ },
|
|
|
+ });
|
|
|
const promotionWithRelations = await this.customFieldRelationService.updateRelations(
|
|
|
ctx,
|
|
|
Promotion,
|
|
|
@@ -149,22 +158,34 @@ export class PromotionService {
|
|
|
const promotion = await this.connection.getEntityOrThrow(ctx, Promotion, input.id, {
|
|
|
channelId: ctx.channelId,
|
|
|
});
|
|
|
- const updatedPromotion = patchEntity(promotion, omit(input, ['conditions', 'actions']));
|
|
|
- if (input.conditions) {
|
|
|
- updatedPromotion.conditions = input.conditions.map(c =>
|
|
|
- this.configArgService.parseInput('PromotionCondition', c),
|
|
|
- );
|
|
|
- }
|
|
|
- if (input.actions) {
|
|
|
- updatedPromotion.actions = input.actions.map(a =>
|
|
|
- this.configArgService.parseInput('PromotionAction', a),
|
|
|
- );
|
|
|
- }
|
|
|
- if (promotion.conditions.length === 0 && !promotion.couponCode) {
|
|
|
+
|
|
|
+ const hasConditions = input.conditions
|
|
|
+ ? input.conditions.length > 0
|
|
|
+ : promotion.conditions.length > 0;
|
|
|
+ const hasCouponCode = input.couponCode != null ? !!input.couponCode : !!promotion.couponCode;
|
|
|
+ if (!hasConditions && !hasCouponCode) {
|
|
|
return new MissingConditionsError();
|
|
|
}
|
|
|
- promotion.priorityScore = this.calculatePriorityScore(input);
|
|
|
- await this.connection.getRepository(ctx, Promotion).save(updatedPromotion, { reload: false });
|
|
|
+ const updatedPromotion = await this.translatableSaver.update({
|
|
|
+ ctx,
|
|
|
+ input,
|
|
|
+ entityType: Promotion,
|
|
|
+ translationType: PromotionTranslation,
|
|
|
+ beforeSave: async p => {
|
|
|
+ p.priorityScore = this.calculatePriorityScore(input);
|
|
|
+ if (input.conditions) {
|
|
|
+ p.conditions = input.conditions.map(c =>
|
|
|
+ this.configArgService.parseInput('PromotionCondition', c),
|
|
|
+ );
|
|
|
+ }
|
|
|
+ if (input.actions) {
|
|
|
+ p.actions = input.actions.map(a =>
|
|
|
+ this.configArgService.parseInput('PromotionAction', a),
|
|
|
+ );
|
|
|
+ }
|
|
|
+ await this.channelService.assignToCurrentChannel(p, ctx);
|
|
|
+ },
|
|
|
+ });
|
|
|
await this.customFieldRelationService.updateRelations(ctx, Promotion, input, updatedPromotion);
|
|
|
this.eventBus.publish(new PromotionEvent(ctx, promotion, 'updated', input));
|
|
|
return assertFound(this.findOne(ctx, updatedPromotion.id));
|
|
|
@@ -200,7 +221,7 @@ export class PromotionService {
|
|
|
for (const promotion of promotions) {
|
|
|
await this.channelService.assignToChannels(ctx, Promotion, promotion.id, [input.channelId]);
|
|
|
}
|
|
|
- return promotions;
|
|
|
+ return promotions.map(p => this.translator.translate(p, ctx));
|
|
|
}
|
|
|
|
|
|
async removePromotionsFromChannel(ctx: RequestContext, input: RemovePromotionsFromChannelInput) {
|
|
|
@@ -218,7 +239,7 @@ export class PromotionService {
|
|
|
for (const promotion of promotions) {
|
|
|
await this.channelService.removeFromChannels(ctx, Promotion, promotion.id, [input.channelId]);
|
|
|
}
|
|
|
- return promotions;
|
|
|
+ return promotions.map(p => this.translator.translate(p, ctx));
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -264,11 +285,13 @@ export class PromotionService {
|
|
|
.getRepository(ctx, Promotion)
|
|
|
.createQueryBuilder('promotion')
|
|
|
.leftJoin('promotion.channels', 'channel')
|
|
|
+ .leftJoinAndSelect('promotion.translations', 'translation')
|
|
|
.where('channel.id = :channelId', { channelId: ctx.channelId })
|
|
|
.andWhere('promotion.deletedAt IS NULL')
|
|
|
.andWhere('promotion.enabled = :enabled', { enabled: true })
|
|
|
.orderBy('promotion.priorityScore', 'ASC')
|
|
|
- .getMany();
|
|
|
+ .getMany()
|
|
|
+ .then(promotions => promotions.map(p => this.translator.translate(p, ctx)));
|
|
|
}
|
|
|
|
|
|
async getActivePromotionsOnOrder(ctx: RequestContext, orderId: ID): Promise<Promotion[]> {
|