Browse Source

feat(core): Add date range and couponCode to Promotion entity

Relates to #174
Michael Bromley 6 years ago
parent
commit
e615d2f30b

+ 15 - 0
packages/admin-ui/src/app/common/generated-types.ts

@@ -524,6 +524,9 @@ export type CreateProductVariantOptionInput = {
 export type CreatePromotionInput = {
   name: Scalars['String'],
   enabled: Scalars['Boolean'],
+  startsAt?: Maybe<Scalars['DateTime']>,
+  endsAt?: Maybe<Scalars['DateTime']>,
+  couponCode?: Maybe<Scalars['String']>,
   conditions: Array<ConfigurableOperationInput>,
   actions: Array<ConfigurableOperationInput>,
 };
@@ -2629,6 +2632,9 @@ export type Promotion = Node & {
   id: Scalars['ID'],
   createdAt: Scalars['DateTime'],
   updatedAt: Scalars['DateTime'],
+  startsAt?: Maybe<Scalars['DateTime']>,
+  endsAt?: Maybe<Scalars['DateTime']>,
+  couponCode?: Maybe<Scalars['String']>,
   name: Scalars['String'],
   enabled: Scalars['Boolean'],
   conditions: Array<ConfigurableOperation>,
@@ -2638,6 +2644,9 @@ export type Promotion = Node & {
 export type PromotionFilterParameter = {
   createdAt?: Maybe<DateOperators>,
   updatedAt?: Maybe<DateOperators>,
+  startsAt?: Maybe<DateOperators>,
+  endsAt?: Maybe<DateOperators>,
+  couponCode?: Maybe<StringOperators>,
   name?: Maybe<StringOperators>,
   enabled?: Maybe<BooleanOperators>,
 };
@@ -2659,6 +2668,9 @@ export type PromotionSortParameter = {
   id?: Maybe<SortOrder>,
   createdAt?: Maybe<SortOrder>,
   updatedAt?: Maybe<SortOrder>,
+  startsAt?: Maybe<SortOrder>,
+  endsAt?: Maybe<SortOrder>,
+  couponCode?: Maybe<SortOrder>,
   name?: Maybe<SortOrder>,
 };
 
@@ -3403,6 +3415,9 @@ export type UpdatePromotionInput = {
   id: Scalars['ID'],
   name?: Maybe<Scalars['String']>,
   enabled?: Maybe<Scalars['Boolean']>,
+  startsAt?: Maybe<Scalars['DateTime']>,
+  endsAt?: Maybe<Scalars['DateTime']>,
+  couponCode?: Maybe<Scalars['String']>,
   conditions?: Maybe<Array<ConfigurableOperationInput>>,
   actions?: Maybe<Array<ConfigurableOperationInput>>,
 };

+ 3 - 0
packages/common/src/generated-shop-types.ts

@@ -1842,6 +1842,9 @@ export type Promotion = Node & {
     id: Scalars['ID'];
     createdAt: Scalars['DateTime'];
     updatedAt: Scalars['DateTime'];
+    startsAt?: Maybe<Scalars['DateTime']>;
+    endsAt?: Maybe<Scalars['DateTime']>;
+    couponCode?: Maybe<Scalars['String']>;
     name: Scalars['String'];
     enabled: Scalars['Boolean'];
     conditions: Array<ConfigurableOperation>;

+ 15 - 0
packages/common/src/generated-types.ts

@@ -523,6 +523,9 @@ export type CreateProductVariantOptionInput = {
 export type CreatePromotionInput = {
   name: Scalars['String'],
   enabled: Scalars['Boolean'],
+  startsAt?: Maybe<Scalars['DateTime']>,
+  endsAt?: Maybe<Scalars['DateTime']>,
+  couponCode?: Maybe<Scalars['String']>,
   conditions: Array<ConfigurableOperationInput>,
   actions: Array<ConfigurableOperationInput>,
 };
@@ -2606,6 +2609,9 @@ export type Promotion = Node & {
   id: Scalars['ID'],
   createdAt: Scalars['DateTime'],
   updatedAt: Scalars['DateTime'],
+  startsAt?: Maybe<Scalars['DateTime']>,
+  endsAt?: Maybe<Scalars['DateTime']>,
+  couponCode?: Maybe<Scalars['String']>,
   name: Scalars['String'],
   enabled: Scalars['Boolean'],
   conditions: Array<ConfigurableOperation>,
@@ -2615,6 +2621,9 @@ export type Promotion = Node & {
 export type PromotionFilterParameter = {
   createdAt?: Maybe<DateOperators>,
   updatedAt?: Maybe<DateOperators>,
+  startsAt?: Maybe<DateOperators>,
+  endsAt?: Maybe<DateOperators>,
+  couponCode?: Maybe<StringOperators>,
   name?: Maybe<StringOperators>,
   enabled?: Maybe<BooleanOperators>,
 };
@@ -2636,6 +2645,9 @@ export type PromotionSortParameter = {
   id?: Maybe<SortOrder>,
   createdAt?: Maybe<SortOrder>,
   updatedAt?: Maybe<SortOrder>,
+  startsAt?: Maybe<SortOrder>,
+  endsAt?: Maybe<SortOrder>,
+  couponCode?: Maybe<SortOrder>,
   name?: Maybe<SortOrder>,
 };
 
@@ -3372,6 +3384,9 @@ export type UpdatePromotionInput = {
   id: Scalars['ID'],
   name?: Maybe<Scalars['String']>,
   enabled?: Maybe<Scalars['Boolean']>,
+  startsAt?: Maybe<Scalars['DateTime']>,
+  endsAt?: Maybe<Scalars['DateTime']>,
+  couponCode?: Maybe<Scalars['String']>,
   conditions?: Maybe<Array<ConfigurableOperationInput>>,
   actions?: Maybe<Array<ConfigurableOperationInput>>,
 };

+ 6 - 0
packages/core/e2e/__snapshots__/promotion.e2e-spec.ts.snap

@@ -69,8 +69,11 @@ Object {
       "code": "promo_condition",
     },
   ],
+  "couponCode": "TEST123",
   "enabled": true,
+  "endsAt": "2019-11-30T23:00:00.000Z",
   "name": "test promotion",
+  "startsAt": "2019-10-29T23:00:00.000Z",
 }
 `;
 
@@ -110,7 +113,10 @@ Object {
       "code": "promo_condition2",
     },
   ],
+  "couponCode": "TEST1235",
   "enabled": true,
+  "endsAt": "2019-05-31T22:00:00.000Z",
   "name": "test promotion",
+  "startsAt": "2019-05-29T22:00:00.000Z",
 }
 `;

+ 3 - 0
packages/core/e2e/graphql/fragments.ts

@@ -401,6 +401,9 @@ export const PROMOTION_FRAGMENT = gql`
         id
         createdAt
         updatedAt
+        couponCode
+        startsAt
+        endsAt
         name
         enabled
         conditions {

+ 16 - 1
packages/core/e2e/graphql/generated-e2e-admin-types.ts

@@ -523,6 +523,9 @@ export type CreateProductVariantOptionInput = {
 export type CreatePromotionInput = {
     name: Scalars['String'];
     enabled: Scalars['Boolean'];
+    startsAt?: Maybe<Scalars['DateTime']>;
+    endsAt?: Maybe<Scalars['DateTime']>;
+    couponCode?: Maybe<Scalars['String']>;
     conditions: Array<ConfigurableOperationInput>;
     actions: Array<ConfigurableOperationInput>;
 };
@@ -2539,6 +2542,9 @@ export type Promotion = Node & {
     id: Scalars['ID'];
     createdAt: Scalars['DateTime'];
     updatedAt: Scalars['DateTime'];
+    startsAt?: Maybe<Scalars['DateTime']>;
+    endsAt?: Maybe<Scalars['DateTime']>;
+    couponCode?: Maybe<Scalars['String']>;
     name: Scalars['String'];
     enabled: Scalars['Boolean'];
     conditions: Array<ConfigurableOperation>;
@@ -2548,6 +2554,9 @@ export type Promotion = Node & {
 export type PromotionFilterParameter = {
     createdAt?: Maybe<DateOperators>;
     updatedAt?: Maybe<DateOperators>;
+    startsAt?: Maybe<DateOperators>;
+    endsAt?: Maybe<DateOperators>;
+    couponCode?: Maybe<StringOperators>;
     name?: Maybe<StringOperators>;
     enabled?: Maybe<BooleanOperators>;
 };
@@ -2569,6 +2578,9 @@ export type PromotionSortParameter = {
     id?: Maybe<SortOrder>;
     createdAt?: Maybe<SortOrder>;
     updatedAt?: Maybe<SortOrder>;
+    startsAt?: Maybe<SortOrder>;
+    endsAt?: Maybe<SortOrder>;
+    couponCode?: Maybe<SortOrder>;
     name?: Maybe<SortOrder>;
 };
 
@@ -3271,6 +3283,9 @@ export type UpdatePromotionInput = {
     id: Scalars['ID'];
     name?: Maybe<Scalars['String']>;
     enabled?: Maybe<Scalars['Boolean']>;
+    startsAt?: Maybe<Scalars['DateTime']>;
+    endsAt?: Maybe<Scalars['DateTime']>;
+    couponCode?: Maybe<Scalars['String']>;
     conditions?: Maybe<Array<ConfigurableOperationInput>>;
     actions?: Maybe<Array<ConfigurableOperationInput>>;
 };
@@ -4055,7 +4070,7 @@ export type OrderWithLinesFragment = { __typename?: 'Order' } & Pick<
 
 export type PromotionFragment = { __typename?: 'Promotion' } & Pick<
     Promotion,
-    'id' | 'createdAt' | 'updatedAt' | 'name' | 'enabled'
+    'id' | 'createdAt' | 'updatedAt' | 'couponCode' | 'startsAt' | 'endsAt' | 'name' | 'enabled'
 > & {
         conditions: Array<{ __typename?: 'ConfigurableOperation' } & ConfigurableOperationFragment>;
         actions: Array<{ __typename?: 'ConfigurableOperation' } & ConfigurableOperationFragment>;

+ 3 - 0
packages/core/e2e/graphql/generated-e2e-shop-types.ts

@@ -1842,6 +1842,9 @@ export type Promotion = Node & {
     id: Scalars['ID'];
     createdAt: Scalars['DateTime'];
     updatedAt: Scalars['DateTime'];
+    startsAt?: Maybe<Scalars['DateTime']>;
+    endsAt?: Maybe<Scalars['DateTime']>;
+    couponCode?: Maybe<Scalars['String']>;
     name: Scalars['String'];
     enabled: Scalars['Boolean'];
     conditions: Array<ConfigurableOperation>;

+ 15 - 3
packages/core/e2e/promotion.e2e-spec.ts

@@ -33,9 +33,15 @@ describe('Promotion resolver', () => {
 
     const promoAction = generateTestAction('promo_action');
 
-    const snapshotProps = ['name', 'actions', 'conditions', 'enabled'] as Array<
-        'name' | 'actions' | 'conditions' | 'enabled'
-    >;
+    const snapshotProps: Array<keyof Promotion.Fragment> = [
+        'name',
+        'actions',
+        'conditions',
+        'enabled',
+        'couponCode',
+        'startsAt',
+        'endsAt',
+    ];
     let promotion: Promotion.Fragment;
 
     beforeAll(async () => {
@@ -65,6 +71,9 @@ describe('Promotion resolver', () => {
                 input: {
                     name: 'test promotion',
                     enabled: true,
+                    couponCode: 'TEST123',
+                    startsAt: new Date(2019, 9, 30),
+                    endsAt: new Date(2019, 11, 1),
                     conditions: [
                         {
                             code: promoCondition.code,
@@ -96,6 +105,9 @@ describe('Promotion resolver', () => {
             {
                 input: {
                     id: promotion.id,
+                    couponCode: 'TEST1235',
+                    startsAt: new Date(2019, 4, 30),
+                    endsAt: new Date(2019, 5, 1),
                     conditions: [
                         {
                             code: promoCondition.code,

+ 6 - 0
packages/core/src/api/schema/admin-api/promotion.api.graphql

@@ -17,6 +17,9 @@ input PromotionListOptions
 input CreatePromotionInput {
     name: String!
     enabled: Boolean!
+    startsAt: DateTime
+    endsAt: DateTime
+    couponCode: String
     conditions: [ConfigurableOperationInput!]!
     actions: [ConfigurableOperationInput!]!
 }
@@ -25,6 +28,9 @@ input UpdatePromotionInput {
     id: ID!
     name: String
     enabled: Boolean
+    startsAt: DateTime
+    endsAt: DateTime
+    couponCode: String
     conditions: [ConfigurableOperationInput!]
     actions: [ConfigurableOperationInput!]
 }

+ 3 - 0
packages/core/src/api/schema/type/promotion.type.graphql

@@ -2,6 +2,9 @@ type Promotion implements Node {
     id: ID!
     createdAt: DateTime!
     updatedAt: DateTime!
+    startsAt: DateTime
+    endsAt: DateTime
+    couponCode: String
     name: String!
     enabled: Boolean!
     conditions: [ConfigurableOperation!]!

+ 1 - 19
packages/core/src/config/promotion/default-promotion-conditions.ts

@@ -21,19 +21,6 @@ export const minimumOrderAmount = new PromotionCondition({
     priorityValue: 10,
 });
 
-export const dateRange = new PromotionCondition({
-    code: 'date_range',
-    description: [{ languageCode: LanguageCode.en, value: 'If Order placed between { start } and { end }' }],
-    args: {
-        start: { type: 'datetime' },
-        end: { type: 'datetime' },
-    },
-    check(order: Order, args) {
-        const now = new Date();
-        return args.start < now && now < args.end;
-    },
-});
-
 export const atLeastNOfProduct = new PromotionCondition({
     code: 'at_least_n_of_product',
     description: [{ languageCode: LanguageCode.en, value: 'Buy at least { minimum } of any product' }],
@@ -68,9 +55,4 @@ export const atLeastNWithFacets = new PromotionCondition({
     },
 });
 
-export const defaultPromotionConditions = [
-    minimumOrderAmount,
-    dateRange,
-    atLeastNOfProduct,
-    atLeastNWithFacets,
-];
+export const defaultPromotionConditions = [minimumOrderAmount, atLeastNOfProduct, atLeastNWithFacets];

+ 9 - 0
packages/core/src/entity/promotion/promotion.entity.ts

@@ -62,6 +62,15 @@ export class Promotion extends AdjustmentSource implements ChannelAware, SoftDel
     @Column({ type: Date, nullable: true, default: null })
     deletedAt: Date | null;
 
+    @Column({ type: Date, nullable: true, default: null })
+    startsAt: Date | null;
+
+    @Column({ type: Date, nullable: true, default: null })
+    endsAt: Date | null;
+
+    @Column({ nullable: true, default: null })
+    couponCode: string;
+
     @Column() name: string;
 
     @Column() enabled: boolean;

+ 3 - 0
packages/core/src/service/services/promotion.service.ts

@@ -85,6 +85,9 @@ export class PromotionService {
         const adjustmentSource = new Promotion({
             name: input.name,
             enabled: input.enabled,
+            couponCode: input.couponCode,
+            startsAt: input.startsAt,
+            endsAt: input.endsAt,
             conditions: input.conditions.map(c => this.parseOperationArgs('condition', c)),
             actions: input.actions.map(a => this.parseOperationArgs('action', a)),
             priorityScore: this.calculatePriorityScore(input),