Browse Source

fix(core): Correctly handle addItemToOrder when 0 stock available

Michael Bromley 5 years ago
parent
commit
187cf3dde6

+ 25 - 0
packages/core/e2e/stock-control.e2e-spec.ts

@@ -443,6 +443,13 @@ describe('Stock control', () => {
                             trackInventory: GlobalFlag.TRUE,
                             useGlobalOutOfStockThreshold: true,
                         },
+                        {
+                            id: 'T_5',
+                            stockOnHand: 0,
+                            outOfStockThreshold: 0,
+                            trackInventory: GlobalFlag.TRUE,
+                            useGlobalOutOfStockThreshold: false,
+                        },
                     ],
                 },
             );
@@ -450,6 +457,24 @@ describe('Stock control', () => {
             await shopClient.asUserWithCredentials('trevor_donnelly96@hotmail.com', 'test');
         });
 
+        it('does not add an empty OrderLine if zero saleable stock', async () => {
+            const variantId = 'T_5';
+            const { addItemToOrder } = await shopClient.query<
+                AddItemToOrder.Mutation,
+                AddItemToOrder.Variables
+            >(ADD_ITEM_TO_ORDER, {
+                productVariantId: variantId,
+                quantity: 1,
+            });
+
+            orderGuard.assertErrorResult(addItemToOrder);
+
+            expect(addItemToOrder.errorCode).toBe(ErrorCode.INSUFFICIENT_STOCK_ERROR);
+            expect(addItemToOrder.message).toBe(`No items were added to the order due to insufficient stock`);
+            expect((addItemToOrder as any).quantityAvailable).toBe(0);
+            expect((addItemToOrder as any).order.lines.length).toBe(0);
+        });
+
         it('returns InsufficientStockError when tracking inventory', async () => {
             const variantId = 'T_1';
             const { addItemToOrder } = await shopClient.query<

+ 3 - 3
packages/core/src/service/helpers/order-calculator/order-calculator.ts

@@ -182,7 +182,7 @@ export class OrderCalculator {
             // which affected the order price.
             const applicablePromotions = await filterAsync(promotions, p => p.test(ctx, order));
 
-            const lineHasExistingPromotions = !!line.items[0].adjustments?.find(
+            const lineHasExistingPromotions = !!line.items[0]?.adjustments?.find(
                 a => a.type === AdjustmentType.PROMOTION,
             );
             const forceUpdateItems = this.orderLineHasInapplicablePromotions(applicablePromotions, line);
@@ -221,8 +221,8 @@ export class OrderCalculator {
                 }
             }
             const lineNoLongerHasPromotions =
-                !line.items[0].adjustments ||
-                !line.items[0].adjustments.find(a => a.type === AdjustmentType.PROMOTION);
+                !line.items[0]?.adjustments ||
+                !line.items[0]?.adjustments.find(a => a.type === AdjustmentType.PROMOTION);
             if (lineHasExistingPromotions && lineNoLongerHasPromotions) {
                 line.items.forEach(i => updatedOrderItems.add(i));
             }

+ 9 - 7
packages/core/src/service/services/order.service.ts

@@ -76,6 +76,7 @@ import { OrderLine } from '../../entity/order-line/order-line.entity';
 import { OrderModification } from '../../entity/order-modification/order-modification.entity';
 import { Order } from '../../entity/order/order.entity';
 import { Payment } from '../../entity/payment/payment.entity';
+import { ProductVariant } from '../../entity/product-variant/product-variant.entity';
 import { Promotion } from '../../entity/promotion/promotion.entity';
 import { Refund } from '../../entity/refund/refund.entity';
 import { ShippingLine } from '../../entity/shipping-line/shipping-line.entity';
@@ -353,20 +354,21 @@ export class OrderService {
         if (validationError) {
             return validationError;
         }
-        const orderLine = await this.orderModifier.getOrCreateItemOrderLine(
-            ctx,
-            order,
-            productVariantId,
-            customFields,
-        );
+        const variant = await this.connection.getEntityOrThrow(ctx, ProductVariant, productVariantId);
         const correctedQuantity = await this.orderModifier.constrainQuantityToSaleable(
             ctx,
-            orderLine.productVariant,
+            variant,
             quantity,
         );
         if (correctedQuantity === 0) {
             return new InsufficientStockError(correctedQuantity, order);
         }
+        const orderLine = await this.orderModifier.getOrCreateItemOrderLine(
+            ctx,
+            order,
+            productVariantId,
+            customFields,
+        );
         await this.orderModifier.updateOrderLineQuantity(
             ctx,
             orderLine,