Ver Fonte

Merge branch 'master' into minor

Michael Bromley há 3 anos atrás
pai
commit
30d615af6c

+ 12 - 2
packages/core/e2e/list-query-builder.e2e-spec.ts

@@ -975,6 +975,14 @@ describe('ListQueryBuilder', () => {
                 { languageCode: LanguageCode.de, name: 'fahrrad' },
             ],
         ];
+        function getTestEntityTranslations(testEntities: { items: any[] }) {
+            // Explicitly sort the order of the translations as it was being non-deterministic on
+            // the mysql CI tests.
+            return testEntities.items.map((e: any) =>
+                e.translations.sort((a: any, b: any) => (a.languageCode < b.languageCode ? 1 : -1)),
+            );
+        }
+
         it('returns all translations with default languageCode', async () => {
             const { testEntities } = await shopClient.query(GET_LIST_WITH_TRANSLATIONS, {
                 options: {
@@ -985,8 +993,9 @@ describe('ListQueryBuilder', () => {
                 },
             });
 
+            const testEntityTranslations = getTestEntityTranslations(testEntities);
             expect(testEntities.items.map((e: any) => e.name)).toEqual(['apple', 'bike']);
-            expect(testEntities.items.map((e: any) => e.translations)).toEqual(allTranslations);
+            expect(testEntityTranslations).toEqual(allTranslations);
         });
         it('returns all translations with non-default languageCode', async () => {
             const { testEntities } = await shopClient.query(
@@ -1002,8 +1011,9 @@ describe('ListQueryBuilder', () => {
                 { languageCode: LanguageCode.de },
             );
 
+            const testEntityTranslations = getTestEntityTranslations(testEntities);
             expect(testEntities.items.map((e: any) => e.name)).toEqual(['apfel', 'fahrrad']);
-            expect(testEntities.items.map((e: any) => e.translations)).toEqual(allTranslations);
+            expect(testEntityTranslations).toEqual(allTranslations);
         });
     });
 });

+ 29 - 0
packages/core/e2e/product.e2e-spec.ts

@@ -26,6 +26,8 @@ import {
     GetProductVariantList,
     GetProductWithVariantList,
     GetProductWithVariants,
+    GetProductWithVariantsQuery,
+    GetProductWithVariantsQueryVariables,
     LanguageCode,
     ProductVariantFragment,
     ProductVariantListOptions,
@@ -1304,6 +1306,33 @@ describe('Product resolver', () => {
             expect(removeOptionGroupFromProduct.productVariantCount).toBe(2);
         });
 
+        it('removeOptionGroupFromProduct succeeds if all related ProductVariants are also deleted', async () => {
+            const { product } = await adminClient.query<
+                GetProductWithVariantsQuery,
+                GetProductWithVariantsQueryVariables
+            >(GET_PRODUCT_WITH_VARIANTS, { id: 'T_2' });
+
+            // Delete all variants for that product
+            for (const variant of product!.variants) {
+                await adminClient.query<DeleteProductVariant.Mutation, DeleteProductVariant.Variables>(
+                    DELETE_PRODUCT_VARIANT,
+                    {
+                        id: variant.id,
+                    },
+                );
+            }
+
+            const { removeOptionGroupFromProduct } = await adminClient.query<
+                RemoveOptionGroupFromProduct.Mutation,
+                RemoveOptionGroupFromProduct.Variables
+            >(REMOVE_OPTION_GROUP_FROM_PRODUCT, {
+                optionGroupId: product!.optionGroups[0].id,
+                productId: product!.id,
+            });
+
+            removeOptionGuard.assertSuccess(removeOptionGroupFromProduct);
+        });
+
         it(
             'removeOptionGroupFromProduct errors with an invalid productId',
             assertThrowsWithMessage(

+ 7 - 0
packages/core/src/config/entity-id-strategy/entity-id-strategy.ts

@@ -12,6 +12,13 @@ export type PrimaryKeyType<T> = T extends 'uuid' ? string : T extends 'increment
  * but custom strategies can be used, e.g. to apply some custom encoding to the ID before exposing
  * it in the GraphQL API.
  *
+ * {{% alert "warning" %}}
+ * Note: changing from an integer-based strategy to a uuid-based strategy
+ * on an existing Vendure database will lead to problems with broken foreign-key
+ * references. To change primary key types like this, you'll need to start with
+ * a fresh database.
+ * {{% /alert %}}
+ *
  * @docsCategory configuration
  * @docsPage EntityIdStrategy
  * */

+ 9 - 0
packages/core/src/config/vendure-config.ts

@@ -842,6 +842,8 @@ export interface JobQueueOptions {
  *
  * @since 1.3.0
  * @docsCategory configuration
+ * @docsPage EntityOptions
+ * @docsWeight 0
  */
 export interface EntityOptions {
     /**
@@ -851,6 +853,13 @@ export interface EntityOptions {
      * entities via the API. The default uses a simple auto-increment integer
      * strategy.
      *
+     * {{% alert "warning" %}}
+     * Note: changing from an integer-based strategy to a uuid-based strategy
+     * on an existing Vendure database will lead to problems with broken foreign-key
+     * references. To change primary key types like this, you'll need to start with
+     * a fresh database.
+     * {{% /alert %}}
+     *
      * @since 1.3.0
      * @default AutoIncrementIdStrategy
      */

+ 4 - 0
packages/core/src/migrate.ts

@@ -7,6 +7,7 @@ import { MysqlDriver } from 'typeorm/driver/mysql/MysqlDriver';
 import { camelCase } from 'typeorm/util/StringUtils';
 
 import { preBootstrapConfig } from './bootstrap';
+import { resetConfig } from './config/config-helpers';
 import { VendureConfig } from './config/vendure-config';
 
 /**
@@ -52,6 +53,7 @@ export async function runMigrations(userConfig: Partial<VendureConfig>) {
         process.exitCode = 1;
     } finally {
         await connection.close();
+        resetConfig();
     }
 }
 
@@ -75,6 +77,7 @@ export async function revertLastMigration(userConfig: Partial<VendureConfig>) {
         process.exitCode = 1;
     } finally {
         await connection.close();
+        resetConfig();
     }
 }
 
@@ -156,6 +159,7 @@ export async function generateMigration(userConfig: Partial<VendureConfig>, opti
         console.log(chalk.yellow(`No changes in database schema were found - cannot generate a migration.`));
     }
     await connection.close();
+    resetConfig();
 }
 
 function createConnectionOptions(userConfig: Partial<VendureConfig>): ConnectionOptions {

+ 9 - 4
packages/core/src/service/helpers/order-modifier/order-modifier.ts

@@ -462,10 +462,15 @@ export class OrderModifier {
         }
 
         const updatedOrderLines = order.lines.filter(l => updatedOrderLineIds.includes(l.id));
-        const promotions = await this.connection.getRepository(ctx, Promotion).find({
-            where: { enabled: true, deletedAt: null },
-            order: { priorityScore: 'ASC' },
-        });
+        const promotions = await this.connection
+            .getRepository(ctx, Promotion)
+            .createQueryBuilder('promotion')
+            .leftJoin('promotion.channels', 'channel')
+            .where('channel.id = :channelId', { channelId: ctx.channelId })
+            .andWhere('promotion.deletedAt IS NULL')
+            .andWhere('promotion.enabled = :enabled', { enabled: true })
+            .orderBy('promotion.priorityScore', 'ASC')
+            .getMany();
         await this.orderCalculator.applyPriceAdjustments(ctx, order, promotions, updatedOrderLines, {
             recalculateShipping: input.options?.recalculateShipping,
         });

+ 11 - 4
packages/core/src/service/services/order.service.ts

@@ -1728,10 +1728,17 @@ export class OrderService {
                 }
             }
         }
-        const { items: promotions } = await this.promotionService.findAll(ctx, {
-            filter: { enabled: { eq: true } },
-            sort: { priorityScore: 'ASC' },
-        });
+
+        const promotions = await this.connection
+            .getRepository(ctx, Promotion)
+            .createQueryBuilder('promotion')
+            .leftJoin('promotion.channels', 'channel')
+            .where('channel.id = :channelId', { channelId: ctx.channelId })
+            .andWhere('promotion.deletedAt IS NULL')
+            .andWhere('promotion.enabled = :enabled', { enabled: true })
+            .orderBy('promotion.priorityScore', 'ASC')
+            .getMany();
+
         const updatedItems = await this.orderCalculator.applyPriceAdjustments(
             ctx,
             order,

+ 6 - 1
packages/core/src/service/services/product.service.ts

@@ -370,7 +370,12 @@ export class ProductService {
         if (!optionGroup) {
             throw new EntityNotFoundError('ProductOptionGroup', optionGroupId);
         }
-        if (product.variants.length) {
+        const optionIsInUse = product.variants.some(
+            variant =>
+                variant.deletedAt == null &&
+                variant.options.some(option => idsAreEqual(option.groupId, optionGroupId)),
+        );
+        if (optionIsInUse) {
             return new ProductOptionInUseError(optionGroup.code, product.variants.length);
         }
         product.optionGroups = product.optionGroups.filter(g => g.id !== optionGroupId);