Преглед на файлове

Merge branch 'master' into minor

Michael Bromley преди 3 години
родител
ревизия
87a0ba3e43

+ 20 - 0
CHANGELOG.md

@@ -1,3 +1,23 @@
+## <small>1.6.4 (2022-07-21)</small>
+
+
+#### Fixes
+
+* **admin-ui** Correctly handle falsy configArg default values ([1d8c30e](https://github.com/vendure-ecommerce/vendure/commit/1d8c30e)), closes [#1663](https://github.com/vendure-ecommerce/vendure/issues/1663)
+* **admin-ui** Display multiple shipping methods in order detail ([b45464e](https://github.com/vendure-ecommerce/vendure/commit/b45464e)), closes [#1665](https://github.com/vendure-ecommerce/vendure/issues/1665)
+* **admin-ui** Fix facet-value-form-input when used with custom fields ([0ae36a9](https://github.com/vendure-ecommerce/vendure/commit/0ae36a9))
+* **admin-ui** Improved handling of failed cancellations ([2c79cf0](https://github.com/vendure-ecommerce/vendure/commit/2c79cf0))
+* **core** Add missing `languageCode` field on ShippingMethod type ([4fab7cf](https://github.com/vendure-ecommerce/vendure/commit/4fab7cf))
+* **core** Correctly resolve translatable custom field relations ([354932c](https://github.com/vendure-ecommerce/vendure/commit/354932c))
+* **core** Fix issue with cancellation of fulfilled OrderItems ([13b0cf9](https://github.com/vendure-ecommerce/vendure/commit/13b0cf9)), closes [#1558](https://github.com/vendure-ecommerce/vendure/issues/1558)
+* **core** Fix order line custom field comparison logic ([dc3ea9c](https://github.com/vendure-ecommerce/vendure/commit/dc3ea9c)), closes [#1670](https://github.com/vendure-ecommerce/vendure/issues/1670)
+* **core** Fix regression when querying custom field relations ([b279d25](https://github.com/vendure-ecommerce/vendure/commit/b279d25)), closes [#1664](https://github.com/vendure-ecommerce/vendure/issues/1664) [#1636](https://github.com/vendure-ecommerce/vendure/issues/1636) [#1636](https://github.com/vendure-ecommerce/vendure/issues/1636)
+* **core** Handle user verification edge case ([1640ea7](https://github.com/vendure-ecommerce/vendure/commit/1640ea7)), closes [#1659](https://github.com/vendure-ecommerce/vendure/issues/1659)
+* **job-queue-plugin** Partially fix BullMQ shutdown error ([3835f8b](https://github.com/vendure-ecommerce/vendure/commit/3835f8b))
+* **payments-plugin** Fix error on Braintree refund failure ([0b79eb5](https://github.com/vendure-ecommerce/vendure/commit/0b79eb5))
+* **payments-plugin** Use idempotency key for Stripe API calls ([9b77d5c](https://github.com/vendure-ecommerce/vendure/commit/9b77d5c))
+* **payments-plugin** Verify Stripe payment intent amount ([b72ae18](https://github.com/vendure-ecommerce/vendure/commit/b72ae18))
+
 ## <small>1.6.3 (2022-07-05)</small>
 
 

+ 1 - 1
lerna.json

@@ -2,7 +2,7 @@
   "packages": [
     "packages/*"
   ],
-  "version": "1.6.3",
+  "version": "1.6.4",
   "npmClient": "yarn",
   "useWorkspaces": true,
   "command": {

+ 3 - 3
packages/admin-ui-plugin/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vendure/admin-ui-plugin",
-  "version": "1.6.3",
+  "version": "1.6.4",
   "main": "lib/index.js",
   "types": "lib/index.d.ts",
   "files": [
@@ -21,8 +21,8 @@
   "devDependencies": {
     "@types/express": "^4.17.8",
     "@types/fs-extra": "^9.0.1",
-    "@vendure/common": "^1.6.3",
-    "@vendure/core": "^1.6.3",
+    "@vendure/common": "^1.6.4",
+    "@vendure/core": "^1.6.4",
     "express": "^4.17.1",
     "rimraf": "^3.0.2",
     "typescript": "4.3.5"

+ 2 - 2
packages/admin-ui/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vendure/admin-ui",
-  "version": "1.6.3",
+  "version": "1.6.4",
   "license": "MIT",
   "scripts": {
     "ng": "ng",
@@ -39,7 +39,7 @@
     "@ng-select/ng-select": "^7.2.0",
     "@ngx-translate/core": "^13.0.0",
     "@ngx-translate/http-loader": "^6.0.0",
-    "@vendure/common": "^1.6.3",
+    "@vendure/common": "^1.6.4",
     "@webcomponents/custom-elements": "^1.4.3",
     "apollo-angular": "^2.6.0",
     "apollo-upload-client": "^16.0.0",

+ 1 - 1
packages/admin-ui/src/lib/core/src/common/version.ts

@@ -1,2 +1,2 @@
 // Auto-generated by the set-version.js script.
-export const ADMIN_UI_VERSION = '1.6.3';
+export const ADMIN_UI_VERSION = '1.6.4';

+ 1 - 1
packages/admin-ui/src/lib/order/src/components/order-table/order-table.component.html

@@ -112,7 +112,7 @@
         </tr>
         <tr class="shipping">
             <td class="left clr-align-middle">{{ 'order.shipping' | translate }}</td>
-            <td class="clr-align-middle">{{ order.shippingLines[0]?.shippingMethod?.name }}</td>
+            <td class="clr-align-middle">{{ getShippingNames(order) }}</td>
             <td colspan="3"></td>
             <td class="clr-align-middle">
                 {{ order.shippingWithTax | localeCurrency: order.currencyCode }}

+ 8 - 0
packages/admin-ui/src/lib/order/src/components/order-table/order-table.component.ts

@@ -72,4 +72,12 @@ export class OrderTableComponent implements OnInit {
             return promotion.couponCode || undefined;
         }
     }
+
+    getShippingNames(order: OrderDetail.Fragment) {
+        if (order.shippingLines.length) {
+            return order.shippingLines.map(shippingLine => shippingLine.shippingMethod.name).join(', ');
+        } else {
+            return '';
+        }
+    }
 }

+ 3 - 3
packages/asset-server-plugin/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vendure/asset-server-plugin",
-  "version": "1.6.3",
+  "version": "1.6.4",
   "main": "lib/index.js",
   "types": "lib/index.d.ts",
   "files": [
@@ -24,8 +24,8 @@
     "@types/fs-extra": "^9.0.8",
     "@types/node-fetch": "^2.5.8",
     "@types/sharp": "^0.30.4",
-    "@vendure/common": "^1.6.3",
-    "@vendure/core": "^1.6.3",
+    "@vendure/common": "^1.6.4",
+    "@vendure/core": "^1.6.4",
     "aws-sdk": "^2.856.0",
     "express": "^4.17.1",
     "node-fetch": "^2.6.1",

+ 1 - 1
packages/common/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vendure/common",
-  "version": "1.6.3",
+  "version": "1.6.4",
   "main": "index.js",
   "license": "MIT",
   "scripts": {

+ 55 - 1
packages/core/e2e/custom-field-relations.e2e-spec.ts

@@ -20,14 +20,16 @@ import {
     RequestContext,
     ShippingMethod,
     TransactionalConnection,
+    VendureEntity,
     VendurePlugin,
 } from '@vendure/core';
 import { createTestEnvironment } from '@vendure/testing';
 import gql from 'graphql-tag';
 import path from 'path';
+import { Entity, JoinColumn, OneToOne } from 'typeorm';
 
 import { initialData } from '../../../e2e-common/e2e-initial-data';
-import { testConfig, TEST_SETUP_TIMEOUT_MS } from '../../../e2e-common/test-config';
+import { TEST_SETUP_TIMEOUT_MS, testConfig } from '../../../e2e-common/test-config';
 
 import { testSuccessfulPaymentMethod } from './fixtures/test-payment-methods';
 import { AddItemToOrder } from './graphql/generated-e2e-shop-types';
@@ -72,6 +74,16 @@ const entitiesWithCustomFields = enumerate<keyof CustomFields>()(
     'Zone',
 );
 
+@Entity()
+class Vendor extends VendureEntity {
+    constructor() {
+        super();
+    }
+    @OneToOne(type => Product, { eager: true })
+    @JoinColumn()
+    featuredProduct: Product;
+}
+
 const customFieldConfig: CustomFields = {};
 for (const entity of entitiesWithCustomFields) {
     customFieldConfig[entity] = [
@@ -90,6 +102,15 @@ customFieldConfig.Product?.push(
     { name: 'cfProduct', type: 'relation', entity: Product, list: false },
     { name: 'cfShippingMethod', type: 'relation', entity: ShippingMethod, list: false },
     { name: 'cfInternalAsset', type: 'relation', entity: Asset, list: false, internal: true },
+    {
+        name: 'cfVendor',
+        type: 'relation',
+        entity: Vendor,
+        graphQLType: 'Vendor',
+        list: false,
+        internal: false,
+        public: true,
+    },
 );
 
 const testResolverSpy = jest.fn();
@@ -110,14 +131,26 @@ class TestResolver1636 {
 
 @VendurePlugin({
     imports: [PluginCommonModule],
+    entities: [Vendor],
     shopApiExtensions: {
         schema: gql`
             extend type Query {
                 getAssetTest(id: ID!): Boolean!
             }
+            type Vendor {
+                featuredProduct: Product
+            }
         `,
         resolvers: [TestResolver1636],
     },
+    adminApiExtensions: {
+        schema: gql`
+            type Vendor {
+                featuredProduct: Product
+            }
+        `,
+        resolvers: [],
+    },
 })
 class TestPlugin1636 {}
 
@@ -125,6 +158,7 @@ const customConfig = mergeConfig(testConfig(), {
     paymentOptions: {
         paymentMethodHandlers: [testSuccessfulPaymentMethod],
     },
+    // logger: new DefaultLogger({ level: LogLevel.Debug }),
     dbConnectionOptions: {
         timezone: 'Z',
     },
@@ -764,6 +798,26 @@ describe('Custom field relations', () => {
                 `);
                 assertCustomFieldIds(updateProductVariants[0].customFields, 'T_2', ['T_3', 'T_4']);
             });
+
+            // https://github.com/vendure-ecommerce/vendure/issues/1664
+            it('successfully gets product with eager-loading custom field relation', async () => {
+                const { product } = await shopClient.query(gql`
+                    query {
+                        product(id: "T_1") {
+                            id
+                            customFields {
+                                cfVendor {
+                                    featuredProduct {
+                                        id
+                                    }
+                                }
+                            }
+                        }
+                    }
+                `);
+
+                expect(product).toBeDefined();
+            });
         });
 
         describe('ProductOptionGroup, ProductOption entity', () => {

+ 88 - 24
packages/core/e2e/shop-order.e2e-spec.ts

@@ -381,6 +381,74 @@ describe('Shop orders', () => {
                 );
             });
 
+            // https://github.com/vendure-ecommerce/vendure/issues/1670
+            it('adding a second item after adjusting custom field adds new OrderLine', async () => {
+                const { addItemToOrder: add1 } = await shopClient.query<AddItemToOrder.Mutation>(
+                    ADD_ITEM_TO_ORDER_WITH_CUSTOM_FIELDS,
+                    {
+                        productVariantId: 'T_3',
+                        quantity: 1,
+                    },
+                );
+                orderResultGuard.assertSuccess(add1);
+                expect(add1!.lines.length).toBe(2);
+                expect(add1!.lines[1].quantity).toBe(1);
+
+                const { adjustOrderLine } = await shopClient.query(ADJUST_ORDER_LINE_WITH_CUSTOM_FIELDS, {
+                    orderLineId: add1.lines[1].id,
+                    quantity: 1,
+                    customFields: {
+                        notes: 'updated notes',
+                    },
+                });
+                expect(adjustOrderLine.lines[1].customFields).toEqual({
+                    lineImage: null,
+                    notes: 'updated notes',
+                });
+                const { activeOrder: ao1 } = await shopClient.query(GET_ORDER_WITH_ORDER_LINE_CUSTOM_FIELDS);
+                expect(ao1.lines[1].customFields).toEqual({
+                    lineImage: null,
+                    notes: 'updated notes',
+                });
+                const updatedNotesLineId = ao1.lines[1].id;
+
+                const { addItemToOrder: add2 } = await shopClient.query<AddItemToOrder.Mutation>(
+                    ADD_ITEM_TO_ORDER_WITH_CUSTOM_FIELDS,
+                    {
+                        productVariantId: 'T_3',
+                        quantity: 1,
+                    },
+                );
+                orderResultGuard.assertSuccess(add2);
+                expect(add2!.lines.length).toBe(3);
+                expect(add2!.lines[1].quantity).toBe(1);
+                expect(add2!.lines[2].quantity).toBe(1);
+
+                const { activeOrder } = await shopClient.query(GET_ORDER_WITH_ORDER_LINE_CUSTOM_FIELDS);
+                expect(activeOrder.lines.find((l: any) => l.id === updatedNotesLineId)?.customFields).toEqual(
+                    {
+                        lineImage: null,
+                        notes: 'updated notes',
+                    },
+                );
+
+                // clean up
+                await shopClient.query<RemoveItemFromOrder.Mutation, RemoveItemFromOrder.Variables>(
+                    REMOVE_ITEM_FROM_ORDER,
+                    {
+                        orderLineId: add2!.lines[1].id,
+                    },
+                );
+                const { removeOrderLine } = await shopClient.query<
+                    RemoveItemFromOrder.Mutation,
+                    RemoveItemFromOrder.Variables
+                >(REMOVE_ITEM_FROM_ORDER, {
+                    orderLineId: add2!.lines[2].id,
+                });
+                orderResultGuard.assertSuccess(removeOrderLine);
+                expect(removeOrderLine.lines.length).toBe(1);
+            });
+
             it('addItemToOrder with relation customField', async () => {
                 const { addItemToOrder } = await shopClient.query<AddItemToOrder.Mutation>(
                     ADD_ITEM_TO_ORDER_WITH_CUSTOM_FIELDS,
@@ -446,28 +514,6 @@ describe('Shop orders', () => {
 
             it('adjustOrderLine updates relation reference', async () => {
                 const { activeOrder } = await shopClient.query(GET_ORDER_WITH_ORDER_LINE_CUSTOM_FIELDS);
-
-                const ADJUST_ORDER_LINE_WITH_CUSTOM_FIELDS = gql`
-                    mutation ($orderLineId: ID!, $quantity: Int!, $customFields: OrderLineCustomFieldsInput) {
-                        adjustOrderLine(
-                            orderLineId: $orderLineId
-                            quantity: $quantity
-                            customFields: $customFields
-                        ) {
-                            ... on Order {
-                                lines {
-                                    id
-                                    customFields {
-                                        notes
-                                        lineImage {
-                                            id
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                `;
                 const { adjustOrderLine } = await shopClient.query(ADJUST_ORDER_LINE_WITH_CUSTOM_FIELDS, {
                     orderLineId: activeOrder.lines[2].id,
                     quantity: 1,
@@ -565,7 +611,7 @@ describe('Shop orders', () => {
                 AdjustItemQuantity.Mutation,
                 AdjustItemQuantity.Variables
             >(ADJUST_ITEM_QUANTITY, {
-                orderLineId: 'T_8',
+                orderLineId: 'T_10',
                 quantity: 101,
             });
             orderResultGuard.assertErrorResult(adjustOrderLine);
@@ -581,7 +627,7 @@ describe('Shop orders', () => {
                 AdjustItemQuantity.Mutation,
                 AdjustItemQuantity.Variables
             >(ADJUST_ITEM_QUANTITY, {
-                orderLineId: 'T_8',
+                orderLineId: 'T_10',
                 quantity: 0,
             });
             orderResultGuard.assertSuccess(adjustLine2);
@@ -2124,3 +2170,21 @@ export const ADD_ITEM_TO_ORDER_WITH_CUSTOM_FIELDS = gql`
     }
     ${UPDATED_ORDER_FRAGMENT}
 `;
+
+const ADJUST_ORDER_LINE_WITH_CUSTOM_FIELDS = gql`
+    mutation ($orderLineId: ID!, $quantity: Int!, $customFields: OrderLineCustomFieldsInput) {
+        adjustOrderLine(orderLineId: $orderLineId, quantity: $quantity, customFields: $customFields) {
+            ... on Order {
+                lines {
+                    id
+                    customFields {
+                        notes
+                        lineImage {
+                            id
+                        }
+                    }
+                }
+            }
+        }
+    }
+`;

+ 2 - 2
packages/core/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vendure/core",
-  "version": "1.6.3",
+  "version": "1.6.4",
   "description": "A modern, headless ecommerce framework",
   "repository": {
     "type": "git",
@@ -49,7 +49,7 @@
     "@nestjs/testing": "7.6.17",
     "@nestjs/typeorm": "7.1.5",
     "@types/fs-extra": "^9.0.1",
-    "@vendure/common": "^1.6.3",
+    "@vendure/common": "^1.6.4",
     "apollo-server-express": "2.24.1",
     "bcrypt": "^5.0.0",
     "body-parser": "^1.19.0",

+ 62 - 0
packages/core/src/connection/transactional-connection.ts

@@ -9,12 +9,14 @@ import {
     FindOptionsUtils,
     ObjectType,
     Repository,
+    SelectQueryBuilder,
 } from 'typeorm';
 
 import { RequestContext } from '../api/common/request-context';
 import { TRANSACTION_MANAGER_KEY } from '../common/constants';
 import { EntityNotFoundError } from '../common/error/errors';
 import { ChannelAware, SoftDeletable } from '../common/types/common-types';
+import { Logger } from '../config/index';
 import { VendureEntity } from '../entity/base/base.entity';
 
 import { TransactionWrapper } from './transaction-wrapper';
@@ -262,6 +264,7 @@ export class TransactionalConnection {
         options: FindOneOptions = {},
     ) {
         const qb = this.getRepository(ctx, entity).createQueryBuilder('entity');
+        options.relations = this.removeCustomFieldsWithEagerRelations(qb, options.relations);
         FindOptionsUtils.applyFindManyOptionsOrConditionsToQueryBuilder(qb, options);
         if (options.loadEagerRelations !== false) {
             // tslint:disable-next-line:no-non-null-assertion
@@ -274,6 +277,65 @@ export class TransactionalConnection {
             .getOne();
     }
 
+    /**
+     * This is a work-around for this issue: https://github.com/vendure-ecommerce/vendure/issues/1664
+     *
+     * Explanation:
+     * When calling `FindOptionsUtils.joinEagerRelations()`, there appears to be a bug in TypeORM whereby
+     * it will throw the following error *if* the `options.relations` array contains any customField relations
+     * where the related entity itself has eagerly-loaded relations.
+     *
+     * For example, let's say we define a custom field on the Product entity like this:
+     * ```
+     * Product: [{
+     *   name: 'featuredFacet',
+     *   type: 'relation',
+     *   entity: Facet,
+     * }],
+     * ```
+     * and then we pass into `TransactionalConnection.findOneInChannel()` an options array of:
+     *
+     * ```
+     * { relations: ['customFields.featuredFacet'] }
+     * ```
+     * it will throw an error because the `Facet` entity itself has eager relations (namely the `translations` property).
+     * This will cause TypeORM to throw the error:
+     * ```
+     * TypeORMError: "entity__customFields" alias was not found. Maybe you forgot to join it?
+     * ```
+     *
+     * So this method introspects the QueryBuilder metadata and checks for any custom field relations which
+     * themselves have eager relations. If found, it removes those items from the `options.relations` array.
+     *
+     * TODO: Ideally create a minimal reproduction case and report in the TypeORM repo for an upstream fix.
+     */
+    private removeCustomFieldsWithEagerRelations(
+        qb: SelectQueryBuilder<any>,
+        relations: string[] = [],
+    ): string[] {
+        let resultingRelations = relations;
+        const mainAlias = qb.expressionMap.mainAlias;
+        const customFieldsMetadata = mainAlias?.metadata.embeddeds.find(
+            metadata => metadata.propertyName === 'customFields',
+        );
+        if (customFieldsMetadata) {
+            const customFieldRelationsWithEagerRelations = customFieldsMetadata.relations.filter(
+                relation => !!relation.inverseEntityMetadata.ownRelations.find(or => or.isEager === true),
+            );
+            for (const relation of customFieldRelationsWithEagerRelations) {
+                const propertyName = relation.propertyName;
+                const relationsToRemove = relations.filter(r => r.startsWith(`customFields.${propertyName}`));
+                if (relationsToRemove.length) {
+                    Logger.debug(
+                        `TransactionalConnection.findOneInChannel cannot automatically join relation [${mainAlias?.metadata.name}.customFields.${propertyName}]`,
+                    );
+                    resultingRelations = relations.filter(r => !r.startsWith(`customFields.${propertyName}`));
+                }
+            }
+        }
+        return resultingRelations;
+    }
+
     /**
      * @description
      * Like the TypeOrm `Repository.findByIds()` method, but limits the results to

+ 8 - 2
packages/core/src/service/helpers/order-modifier/order-modifier.ts

@@ -582,8 +582,14 @@ export class OrderModifier {
             for (const def of customFieldDefs) {
                 const key = def.name;
                 const existingValue = existingCustomFields?.[key];
-                if (existingValue !== null && def.defaultValue && existingValue !== def.defaultValue) {
-                    return false;
+                if (existingValue != null) {
+                    if (def.defaultValue != null) {
+                        if (existingValue !== def.defaultValue) {
+                            return false;
+                        }
+                    } else {
+                        return false;
+                    }
                 }
             }
             return true;

+ 3 - 3
packages/create/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vendure/create",
-  "version": "1.6.3",
+  "version": "1.6.4",
   "license": "MIT",
   "bin": {
     "create": "./index.js"
@@ -28,13 +28,13 @@
     "@types/handlebars": "^4.1.0",
     "@types/listr": "^0.14.2",
     "@types/semver": "^6.2.2",
-    "@vendure/core": "^1.6.3",
+    "@vendure/core": "^1.6.4",
     "rimraf": "^3.0.2",
     "ts-node": "^10.2.1",
     "typescript": "4.3.5"
   },
   "dependencies": {
-    "@vendure/common": "^1.6.3",
+    "@vendure/common": "^1.6.4",
     "chalk": "^4.1.0",
     "commander": "^7.1.0",
     "cross-spawn": "^7.0.3",

+ 9 - 9
packages/dev-server/package.json

@@ -1,6 +1,6 @@
 {
   "name": "dev-server",
-  "version": "1.6.3",
+  "version": "1.6.4",
   "main": "index.js",
   "license": "MIT",
   "private": true,
@@ -14,18 +14,18 @@
     "load-test:100k": "node -r ts-node/register load-testing/run-load-test.ts 100000"
   },
   "dependencies": {
-    "@vendure/admin-ui-plugin": "^1.6.3",
-    "@vendure/asset-server-plugin": "^1.6.3",
-    "@vendure/common": "^1.6.3",
-    "@vendure/core": "^1.6.3",
-    "@vendure/elasticsearch-plugin": "^1.6.3",
-    "@vendure/email-plugin": "^1.6.3",
+    "@vendure/admin-ui-plugin": "^1.6.4",
+    "@vendure/asset-server-plugin": "^1.6.4",
+    "@vendure/common": "^1.6.4",
+    "@vendure/core": "^1.6.4",
+    "@vendure/elasticsearch-plugin": "^1.6.4",
+    "@vendure/email-plugin": "^1.6.4",
     "typescript": "4.3.5"
   },
   "devDependencies": {
     "@types/csv-stringify": "^3.1.0",
-    "@vendure/testing": "^1.6.3",
-    "@vendure/ui-devkit": "^1.6.3",
+    "@vendure/testing": "^1.6.4",
+    "@vendure/ui-devkit": "^1.6.4",
     "commander": "^7.1.0",
     "concurrently": "^5.0.0",
     "csv-stringify": "^5.3.3",

+ 87 - 0
packages/dev-server/test-plugins/issue-1664.ts

@@ -0,0 +1,87 @@
+import {
+    LanguageCode,
+    LocaleString,
+    PluginCommonModule,
+    Product,
+    Translation,
+    VendureEntity,
+    VendurePlugin,
+} from '@vendure/core';
+import gql from 'graphql-tag';
+import { Column, Entity, ManyToOne, OneToMany } from 'typeorm';
+
+@Entity()
+class Vendor extends VendureEntity {
+    constructor(input: Partial<Vendor>) {
+        super(input);
+    }
+
+    description: LocaleString;
+
+    @Column()
+    name: string;
+
+    @OneToMany(() => Product, product => (product.customFields as any).vendor)
+    products: Product[];
+
+    @OneToMany(() => VendorTranslation, translation => translation.base, { eager: true })
+    translations: Array<Translation<Vendor>>;
+}
+
+@Entity()
+export class VendorTranslation extends VendureEntity implements Translation<Vendor> {
+    constructor(input?: Partial<Translation<Vendor>>) {
+        super(input);
+    }
+
+    @Column('varchar')
+    languageCode: LanguageCode;
+
+    @Column('text')
+    description: string;
+
+    @ManyToOne(() => Vendor, vendor => vendor.translations, { onDelete: 'CASCADE' })
+    base: Vendor;
+}
+
+const schema = gql`
+    type Vendor implements Node {
+        id: ID!
+        createdAt: DateTime!
+        updatedAt: DateTime!
+        name: String!
+        description: String!
+    }
+`;
+
+/**
+ * Test plugin for https://github.com/vendure-ecommerce/vendure/issues/1664
+ */
+@VendurePlugin({
+    imports: [PluginCommonModule],
+    entities: [Vendor, VendorTranslation],
+    shopApiExtensions: { schema, resolvers: [] },
+    adminApiExtensions: { schema, resolvers: [] },
+    configuration: config => {
+        config.customFields.Product.push({
+            name: 'vendor',
+            label: [{ languageCode: LanguageCode.en_AU, value: 'Vendor' }],
+            type: 'relation',
+            entity: Vendor,
+            eager: true,
+            nullable: false,
+            defaultValue: null,
+            ui: {
+                component: 'cp-product-vendor-selector',
+            },
+        });
+
+        config.customFields.Product.push({
+            name: 'shopifyId',
+            type: 'float',
+            public: false,
+        });
+        return config;
+    },
+})
+export class Test1664Plugin {}

+ 3 - 3
packages/elasticsearch-plugin/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vendure/elasticsearch-plugin",
-  "version": "1.6.3",
+  "version": "1.6.4",
   "license": "MIT",
   "main": "lib/index.js",
   "types": "lib/index.d.ts",
@@ -25,8 +25,8 @@
     "fast-deep-equal": "^3.1.3"
   },
   "devDependencies": {
-    "@vendure/common": "^1.6.3",
-    "@vendure/core": "^1.6.3",
+    "@vendure/common": "^1.6.4",
+    "@vendure/core": "^1.6.4",
     "rimraf": "^3.0.2",
     "typescript": "4.3.5"
   }

+ 3 - 3
packages/email-plugin/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vendure/email-plugin",
-  "version": "1.6.3",
+  "version": "1.6.4",
   "license": "MIT",
   "main": "lib/index.js",
   "types": "lib/index.d.ts",
@@ -35,8 +35,8 @@
     "@types/fs-extra": "^9.0.1",
     "@types/handlebars": "^4.1.0",
     "@types/mjml": "^4.0.4",
-    "@vendure/common": "^1.6.3",
-    "@vendure/core": "^1.6.3",
+    "@vendure/common": "^1.6.4",
+    "@vendure/core": "^1.6.4",
     "rimraf": "^3.0.2",
     "typescript": "4.3.5"
   }

+ 3 - 3
packages/job-queue-plugin/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vendure/job-queue-plugin",
-  "version": "1.6.3",
+  "version": "1.6.4",
   "license": "MIT",
   "main": "package/index.js",
   "types": "package/index.d.ts",
@@ -24,8 +24,8 @@
   "devDependencies": {
     "@google-cloud/pubsub": "^2.8.0",
     "@types/ioredis": "^4.28.10",
-    "@vendure/common": "^1.6.3",
-    "@vendure/core": "^1.6.3",
+    "@vendure/common": "^1.6.4",
+    "@vendure/core": "^1.6.4",
     "bullmq": "^1.86.7",
     "rimraf": "^3.0.2",
     "typescript": "4.3.5"

+ 4 - 4
packages/payments-plugin/package.json

@@ -1,6 +1,6 @@
 {
     "name": "@vendure/payments-plugin",
-    "version": "1.6.3",
+    "version": "1.6.4",
     "license": "MIT",
     "main": "package/index.js",
     "types": "package/index.d.ts",
@@ -28,9 +28,9 @@
     "devDependencies": {
         "@mollie/api-client": "^3.6.0",
         "@types/braintree": "^2.22.15",
-        "@vendure/common": "^1.6.3",
-        "@vendure/core": "^1.6.3",
-        "@vendure/testing": "^1.6.3",
+        "@vendure/common": "^1.6.4",
+        "@vendure/core": "^1.6.4",
+        "@vendure/testing": "^1.6.4",
         "braintree": "^3.0.0",
         "nock": "^13.1.4",
         "rimraf": "^3.0.2",

+ 3 - 3
packages/testing/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vendure/testing",
-  "version": "1.6.3",
+  "version": "1.6.4",
   "description": "End-to-end testing tools for Vendure projects",
   "keywords": [
     "vendure",
@@ -34,7 +34,7 @@
   },
   "dependencies": {
     "@types/node-fetch": "^2.5.4",
-    "@vendure/common": "^1.6.3",
+    "@vendure/common": "^1.6.4",
     "faker": "^4.1.0",
     "form-data": "^3.0.0",
     "graphql": "15.5.1",
@@ -45,7 +45,7 @@
   "devDependencies": {
     "@types/mysql": "^2.15.15",
     "@types/pg": "^7.14.5",
-    "@vendure/core": "^1.6.3",
+    "@vendure/core": "^1.6.4",
     "mysql": "^2.18.1",
     "pg": "^8.4.0",
     "rimraf": "^3.0.0",

+ 4 - 4
packages/ui-devkit/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vendure/ui-devkit",
-  "version": "1.6.3",
+  "version": "1.6.4",
   "description": "A library for authoring Vendure Admin UI extensions",
   "keywords": [
     "vendure",
@@ -40,8 +40,8 @@
     "@angular/cli": "12.2.16",
     "@angular/compiler": "12.2.16",
     "@angular/compiler-cli": "12.2.16",
-    "@vendure/admin-ui": "^1.6.3",
-    "@vendure/common": "^1.6.3",
+    "@vendure/admin-ui": "^1.6.4",
+    "@vendure/common": "^1.6.4",
     "chalk": "^4.1.0",
     "chokidar": "^3.5.1",
     "fs-extra": "^10.0.0",
@@ -52,7 +52,7 @@
     "@rollup/plugin-node-resolve": "^11.2.0",
     "@types/fs-extra": "^9.0.8",
     "@types/glob": "^7.1.3",
-    "@vendure/core": "^1.6.3",
+    "@vendure/core": "^1.6.4",
     "rimraf": "^3.0.2",
     "rollup": "^2.40.0",
     "rollup-plugin-terser": "^7.0.2",