Skip to content

Commit

Permalink
fix(core): Fix error when resolving deleted Product from Order
Browse files Browse the repository at this point in the history
Fixes #1125
  • Loading branch information
michaelbromley committed Oct 5, 2021
1 parent e6cf34a commit 511f04d
Show file tree
Hide file tree
Showing 10 changed files with 141 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3351,21 +3351,14 @@ export type Product = Node & {
description: Scalars['String'];
featuredAsset?: Maybe<Asset>;
assets: Array<Asset>;
/** Returns all ProductVariants */
variants: Array<ProductVariant>;
/** Returns a paginated, sortable, filterable list of ProductVariants */
variantList: ProductVariantList;
optionGroups: Array<ProductOptionGroup>;
facetValues: Array<FacetValue>;
translations: Array<ProductTranslation>;
collections: Array<Collection>;
customFields?: Maybe<Scalars['JSON']>;
};

export type ProductVariantListArgs = {
options?: Maybe<ProductVariantListOptions>;
};

export type ProductFilterParameter = {
enabled?: Maybe<BooleanOperators>;
createdAt?: Maybe<DateOperators>;
Expand Down
7 changes: 0 additions & 7 deletions packages/common/src/generated-shop-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2303,21 +2303,14 @@ export type Product = Node & {
description: Scalars['String'];
featuredAsset?: Maybe<Asset>;
assets: Array<Asset>;
/** Returns all ProductVariants */
variants: Array<ProductVariant>;
/** Returns a paginated, sortable, filterable list of ProductVariants */
variantList: ProductVariantList;
optionGroups: Array<ProductOptionGroup>;
facetValues: Array<FacetValue>;
translations: Array<ProductTranslation>;
collections: Array<Collection>;
customFields?: Maybe<Scalars['JSON']>;
};

export type ProductVariantListArgs = {
options?: Maybe<ProductVariantListOptions>;
};

export type ProductFilterParameter = {
createdAt?: Maybe<DateOperators>;
updatedAt?: Maybe<DateOperators>;
Expand Down
34 changes: 0 additions & 34 deletions packages/core/e2e/graphql/generated-e2e-admin-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3351,21 +3351,14 @@ export type Product = Node & {
description: Scalars['String'];
featuredAsset?: Maybe<Asset>;
assets: Array<Asset>;
/** Returns all ProductVariants */
variants: Array<ProductVariant>;
/** Returns a paginated, sortable, filterable list of ProductVariants */
variantList: ProductVariantList;
optionGroups: Array<ProductOptionGroup>;
facetValues: Array<FacetValue>;
translations: Array<ProductTranslation>;
collections: Array<Collection>;
customFields?: Maybe<Scalars['JSON']>;
};

export type ProductVariantListArgs = {
options?: Maybe<ProductVariantListOptions>;
};

export type ProductFilterParameter = {
enabled?: Maybe<BooleanOperators>;
createdAt?: Maybe<DateOperators>;
Expand Down Expand Up @@ -6509,19 +6502,6 @@ export type GetProductVariantListQuery = {
};
};

export type GetProductWithVariantListQueryVariables = Exact<{
id?: Maybe<Scalars['ID']>;
variantListOptions?: Maybe<ProductVariantListOptions>;
}>;

export type GetProductWithVariantListQuery = {
product?: Maybe<
Pick<Product, 'id'> & {
variantList: Pick<ProductVariantList, 'totalItems'> & { items: Array<ProductVariantFragment> };
}
>;
};

export type DeletePromotionMutationVariables = Exact<{
id: Scalars['ID'];
}>;
Expand Down Expand Up @@ -8844,20 +8824,6 @@ export namespace GetProductVariantList {
>;
}

export namespace GetProductWithVariantList {
export type Variables = GetProductWithVariantListQueryVariables;
export type Query = GetProductWithVariantListQuery;
export type Product = NonNullable<GetProductWithVariantListQuery['product']>;
export type VariantList = NonNullable<
NonNullable<GetProductWithVariantListQuery['product']>['variantList']
>;
export type Items = NonNullable<
NonNullable<
NonNullable<NonNullable<GetProductWithVariantListQuery['product']>['variantList']>['items']
>[number]
>;
}

export namespace DeletePromotion {
export type Variables = DeletePromotionMutationVariables;
export type Mutation = DeletePromotionMutation;
Expand Down
76 changes: 69 additions & 7 deletions packages/core/e2e/graphql/generated-e2e-shop-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2226,21 +2226,14 @@ export type Product = Node & {
description: Scalars['String'];
featuredAsset?: Maybe<Asset>;
assets: Array<Asset>;
/** Returns all ProductVariants */
variants: Array<ProductVariant>;
/** Returns a paginated, sortable, filterable list of ProductVariants */
variantList: ProductVariantList;
optionGroups: Array<ProductOptionGroup>;
facetValues: Array<FacetValue>;
translations: Array<ProductTranslation>;
collections: Array<Collection>;
customFields?: Maybe<Scalars['JSON']>;
};

export type ProductVariantListArgs = {
options?: Maybe<ProductVariantListOptions>;
};

export type ProductFilterParameter = {
createdAt?: Maybe<DateOperators>;
updatedAt?: Maybe<DateOperators>;
Expand Down Expand Up @@ -3394,6 +3387,16 @@ export type GetProductStockLevelQuery = {
product?: Maybe<Pick<Product, 'id'> & { variants: Array<Pick<ProductVariant, 'id' | 'stockLevel'>> }>;
};

export type GetActiveCustomerWithOrdersProductSlugQueryVariables = Exact<{
options?: Maybe<OrderListOptions>;
}>;

export type GetActiveCustomerWithOrdersProductSlugQuery = {
activeCustomer?: Maybe<{
orders: { items: Array<{ lines: Array<{ productVariant: { product: Pick<Product, 'slug'> } }> }> };
}>;
};

type DiscriminateUnion<T, U> = T extends U ? T : never;

export namespace TestOrderFragment {
Expand Down Expand Up @@ -3921,3 +3924,62 @@ export namespace GetProductStockLevel {
NonNullable<NonNullable<GetProductStockLevelQuery['product']>['variants']>[number]
>;
}

export namespace GetActiveCustomerWithOrdersProductSlug {
export type Variables = GetActiveCustomerWithOrdersProductSlugQueryVariables;
export type Query = GetActiveCustomerWithOrdersProductSlugQuery;
export type ActiveCustomer = NonNullable<GetActiveCustomerWithOrdersProductSlugQuery['activeCustomer']>;
export type Orders = NonNullable<
NonNullable<GetActiveCustomerWithOrdersProductSlugQuery['activeCustomer']>['orders']
>;
export type Items = NonNullable<
NonNullable<
NonNullable<
NonNullable<GetActiveCustomerWithOrdersProductSlugQuery['activeCustomer']>['orders']
>['items']
>[number]
>;
export type Lines = NonNullable<
NonNullable<
NonNullable<
NonNullable<
NonNullable<
NonNullable<GetActiveCustomerWithOrdersProductSlugQuery['activeCustomer']>['orders']
>['items']
>[number]
>['lines']
>[number]
>;
export type ProductVariant = NonNullable<
NonNullable<
NonNullable<
NonNullable<
NonNullable<
NonNullable<
NonNullable<
GetActiveCustomerWithOrdersProductSlugQuery['activeCustomer']
>['orders']
>['items']
>[number]
>['lines']
>[number]
>['productVariant']
>;
export type Product = NonNullable<
NonNullable<
NonNullable<
NonNullable<
NonNullable<
NonNullable<
NonNullable<
NonNullable<
GetActiveCustomerWithOrdersProductSlugQuery['activeCustomer']
>['orders']
>['items']
>[number]
>['lines']
>[number]
>['productVariant']
>['product']
>;
}
18 changes: 18 additions & 0 deletions packages/core/e2e/graphql/shop-definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -703,3 +703,21 @@ export const GET_PRODUCT_WITH_STOCK_LEVEL = gql`
}
}
`;

export const GET_ACTIVE_CUSTOMER_WITH_ORDERS_PRODUCT_SLUG = gql`
query GetActiveCustomerWithOrdersProductSlug($options: OrderListOptions) {
activeCustomer {
orders(options: $options) {
items {
lines {
productVariant {
product {
slug
}
}
}
}
}
}
}
`;
39 changes: 39 additions & 0 deletions packages/core/e2e/order.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
CreateFulfillment,
CreateShippingMethod,
DeleteOrderNote,
DeleteProduct,
DeleteShippingMethod,
ErrorCode,
FulfillmentFragment,
Expand Down Expand Up @@ -69,6 +70,7 @@ import {
AddPaymentToOrder,
ApplyCouponCode,
DeletionResult,
GetActiveCustomerWithOrdersProductSlug,
GetActiveOrder,
GetOrderByCodeWithPayments,
SetShippingAddress,
Expand All @@ -81,6 +83,7 @@ import {
CANCEL_ORDER,
CREATE_FULFILLMENT,
CREATE_SHIPPING_METHOD,
DELETE_PRODUCT,
DELETE_SHIPPING_METHOD,
GET_CUSTOMER_LIST,
GET_ORDER,
Expand All @@ -97,6 +100,7 @@ import {
ADD_ITEM_TO_ORDER,
ADD_PAYMENT,
APPLY_COUPON_CODE,
GET_ACTIVE_CUSTOMER_WITH_ORDERS_PRODUCT_SLUG,
GET_ACTIVE_ORDER,
GET_ORDER_BY_CODE_WITH_PAYMENTS,
SET_SHIPPING_ADDRESS,
Expand Down Expand Up @@ -2213,6 +2217,41 @@ describe('Orders resolver', () => {
});
refundGuard.assertSuccess(refund2);
});

// https://github.com/vendure-ecommerce/vendure/issues/1125
it('resolves deleted Product of OrderLine ProductVariants', async () => {
await shopClient.asUserWithCredentials(customers[0].emailAddress, password);
const { addItemToOrder } = await shopClient.query<
AddItemToOrder.Mutation,
AddItemToOrder.Variables
>(ADD_ITEM_TO_ORDER, {
productVariantId: 'T_7',
quantity: 1,
});

await proceedToArrangingPayment(shopClient);
const order = await addPaymentToOrder(shopClient, singleStageRefundablePaymentMethod);
orderGuard.assertSuccess(order);

await adminClient.query<DeleteProduct.Mutation, DeleteProduct.Variables>(DELETE_PRODUCT, {
id: 'T_3',
});

const { activeCustomer } = await shopClient.query<
GetActiveCustomerWithOrdersProductSlug.Query,
GetActiveCustomerWithOrdersProductSlug.Variables
>(GET_ACTIVE_CUSTOMER_WITH_ORDERS_PRODUCT_SLUG, {
options: {
sort: {
createdAt: SortOrder.ASC,
},
},
});
expect(
activeCustomer!.orders.items[activeCustomer!.orders.items.length - 1].lines[0].productVariant
.product.slug,
).toBe('gaming-pc');
});
});
});

Expand Down
4 changes: 3 additions & 1 deletion packages/core/src/connection/transactional-connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,9 @@ export class TransactionalConnection {
}
if (
!entity ||
(entity.hasOwnProperty('deletedAt') && (entity as T & SoftDeletable).deletedAt !== null)
(entity.hasOwnProperty('deletedAt') &&
(entity as T & SoftDeletable).deletedAt !== null &&
options.includeSoftDeleted !== true)
) {
throw new EntityNotFoundError(entityType.name as any, id);
}
Expand Down
9 changes: 9 additions & 0 deletions packages/core/src/connection/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,13 @@ export interface GetEntityOrThrowOptions<T = any> extends FindOneOptions<T> {
* @default 25
*/
retryDelay?: number;
/**
* @description
* If set to `true`, soft-deleted entities will be returned. Otherwise they will
* throw as if they did not exist.
*
* @since 1.3.0
* @default false
*/
includeSoftDeleted?: boolean;
}
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,9 @@ export class ProductVariantService {
* page, this method returns on the Product itself.
*/
async getProductForVariant(ctx: RequestContext, variant: ProductVariant): Promise<Translated<Product>> {
const product = await this.connection.getEntityOrThrow(ctx, Product, variant.productId);
const product = await this.connection.getEntityOrThrow(ctx, Product, variant.productId, {
includeSoftDeleted: true,
});
return translateDeep(product, ctx.languageCode);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3351,21 +3351,14 @@ export type Product = Node & {
description: Scalars['String'];
featuredAsset?: Maybe<Asset>;
assets: Array<Asset>;
/** Returns all ProductVariants */
variants: Array<ProductVariant>;
/** Returns a paginated, sortable, filterable list of ProductVariants */
variantList: ProductVariantList;
optionGroups: Array<ProductOptionGroup>;
facetValues: Array<FacetValue>;
translations: Array<ProductTranslation>;
collections: Array<Collection>;
customFields?: Maybe<Scalars['JSON']>;
};

export type ProductVariantListArgs = {
options?: Maybe<ProductVariantListOptions>;
};

export type ProductFilterParameter = {
enabled?: Maybe<BooleanOperators>;
createdAt?: Maybe<DateOperators>;
Expand Down

0 comments on commit 511f04d

Please sign in to comment.